How to Fix "UCP Identity Linking broken"
The agent can discover your store, browse your catalog, and add items to cart. But when it tries to access saved addresses, loyalty points, or order history, everything falls apart. The reason: your Identity Linking capability is broken or missing.
What is UCP Identity Linking?
Identity Linking (dev.ucp.common.identity_linking) is the UCP capability that enables an AI agent platform (like Google or ChatGPT) to obtain authorization to act on behalf of a user on your store. It bridges agent-authenticated access to user-authenticated access.
Without Identity Linking, every interaction is anonymous: an agent can browse your public catalog and add items to cart, but cannot access saved addresses, wishlists, loyalty benefits, or order history. Every purchase is a "new customer" transaction.
With it working, the agent can retrieve saved shipping addresses and payment methods, apply loyalty points or member pricing, access purchase history for reordering, and complete checkout as a recognized customer. The v1 spec uses OAuth 2.0 Authorization Code flow - your store is the authorization server; the agent platform is the client.
Why this breaks AI agent experiences
When Identity Linking is broken, agents don't just get an error - they get downgraded to a worse experience:
- Agent reads the Identity Linking capability in your manifest
- Agent attempts to initiate the OAuth flow
- The flow fails - metadata missing, PKCE not enforced, or scopes don't match
- Agent falls back to anonymous access mode
- The user's saved preferences, loyalty discounts, and address are all invisible
- Agent presents a generic experience - or skips your store for one that recognizes the user
The worst part: this failure is silent from your perspective. Your store works fine for human shoppers and your endpoints return 200 - but agents are presenting a degraded experience to your best, repeat customers.
The 5 types of Identity Linking failures
1. Missing Identity Linking capability entirely
No Identity Linking block exists. While technically optional, missing it means you forfeit personalized commerce entirely. For stores with loyalty programs, member pricing, or repeat customers, this is functionally a failure.
2. Missing authorization server metadata
The capability is declared but points to an endpoint instead of an OAuth authorization server. The spec requires you to publish metadata at /.well-known/oauth-authorization-server so the agent can discover token endpoints, supported scopes, and auth methods. Without it, agents cannot complete the flow.
3. Scope mismatches
Your manifest declares scopes (like profile:read, orders:history) that your authorization server doesn't honor, or your server advertises a different set in scopes_supported. The agent requests scopes your server rejects, and the flow fails at the authorization step.
4. PKCE not enforced
UCP requires PKCE (code_challenge_method=S256) for all authorization code exchanges:
Authorization request: code_challenge=XXX&code_challenge_method=S256 Token request: code_verifier=YYY Server MUST: validate that code_challenge == SHA256(code_verifier) Server MUST: reject requests without a valid code_verifier
Agents may detect missing PKCE enforcement during security validation and refuse to complete the flow, even if your server would accept the request.
5. Redirect URI mismatch
The most common cause. Your server's redirect_uris list doesn't include the redirect URI the agent platform uses. The exception: loopback redirects (targeting 127.0.0.1) match on scheme, host, and path only - ignoring the port - per RFC 8252 Section 7.3.
How to fix Identity Linking
Fix 1: Publish authorization server metadata
Create a complete metadata document at /.well-known/oauth-authorization-server:
{
"issuer": "https://yourstore.com",
"authorization_endpoint": "https://yourstore.com/oauth/authorize",
"token_endpoint": "https://yourstore.com/oauth/token",
"token_endpoint_auth_methods_supported": ["private_key_jwt", "client_secret_basic"],
"scopes_supported": ["profile:read", "orders:history", "addresses:read", "loyalty:read"],
"response_types_supported": ["code"],
"code_challenge_methods_supported": ["S256"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"revocation_endpoint": "https://yourstore.com/oauth/revoke"
}Fix 2: Align scopes between manifest and server
The scopes in your manifest's config.scopes must match your server's scopes_supported. The spec explicitly calls this out: publish scopes_supported so platforms can detect mismatches before initiating a flow. If they don't match, the agent fails mid-flow or requests scopes your server rejects.
Fix 3: Enforce PKCE
- Authorization endpoint: accept
code_challengeandcode_challenge_method - Store: persist
code_challengewith the authorization code - Token endpoint: require
code_verifier - Validate: SHA256(
code_verifier) must equal the storedcode_challenge - Reject: return
invalid_grantifcode_verifieris missing or doesn't verify
Fix 4: Configure redirect URIs correctly
{
"redirect_uris": [
"https://yourstore.com/oauth/callback",
"https://accounts.google.com/oauth/return",
"https://chatgpt.com/oauth/callback"
]
}For loopback URIs (native/desktop agent runtimes), match on scheme, host, and path only - ignore the port - per RFC 8252 Section 7.3.
Fix 5: Add issuer validation
Include the iss parameter in every authorization response, and ensure it matches your metadata issuer exactly. Agents validate iss to prevent Mix-Up Attacks.
How to test your fix
Identity Linking spans all four levels. Level 1 and 2 catch missing capability blocks and scope mismatches. Level 3 and 4 are where PKCE enforcement, redirect URI configuration, and token endpoint behavior are actually tested - a metadata document that looks correct on paper can still fail when an agent attempts the real flow. See the four levels of UCP validation.
Test the full OAuth flow, not just the JSON
Run a free 4-level validation - including the Level 4 simulation that attempts the real Authorization Code flow against your store.
Validate Your Store FreeQuick reference: Identity Linking requirements
| Field | Required? | Common Mistake |
|---|---|---|
| Capability block | Optional, functionally essential | Missing for stores with loyalty/repeat customers |
| Authorization server metadata | Yes (for OAuth flow) | Declaring capability without publishing metadata |
config.scopes | Must match scopes_supported | Manifest declares scopes server doesn't support |
| PKCE enforcement | Required by spec | Not validating code_verifier at token endpoint |
| Redirect URIs | Must include agent platform URIs | Only allowing your own callback URL |
| Issuer validation | Required by spec | Missing iss parameter in response |
