Skip to main content

Get a merchant access token

The MCP/UCP service uses two server-side calls to obtain the merchant access token associated with the user's authorization.

Why two tokens are involved​

The agent gives your server the AIGW access token representing the authorized user/agent session. Your server separately proves its own identity to AIGW with a project-level Proxy client credential. AIGW requires both contexts before it returns the merchant access token.

This prevents the agent from directly redeeming merchant credentials and prevents an MCP/UCP server from redeeming a user token from a different AIGW project.

Step 1 — Get a proxy token​

Use OAuth client_credentials against the AIGW core token endpoint:

POST https://core.api.aigw.loginid.ai/oauth2/token
Authorization: Basic base64(<PROXY_CLIENT_ID>:<PROXY_CLIENT_SECRET>)
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

A successful response contains access_token, token_type, and expires_in. Cache the Proxy token until near the returned expiry; do not assume a fixed lifetime.

Step 2 — Redeem for the merchant access token​

The user's AIGW access token must include ext_token:read and come from authorization for this Resource. Call the AIGW credential endpoint:

POST https://api.aigw.loginid.ai/api/credentials/token
Authorization: Bearer <AIGW_ACCESS_TOKEN>
X-Proxy-Token: <PROXY_TOKEN>
Content-Type: application/json

{
"resource": "https://mcp.example.com/mcp"
}
Exact match required

The resource value must exactly match the Resource indicator / audience configured on the AIGW Token exchange Resource. A different URL or trailing slash is not interchangeable.

A successful response contains the merchant access token, and can include its expiry and the scopes the merchant authorization server granted:

{
"access_token": "<MERCHANT_ACCESS_TOKEN>",
"expires_at": "2030-01-01T18:30:00Z",
"scopes": ["search:read"]
}

The merchant refresh token is never returned; AIGW keeps it and refreshes on your behalf. See Credential redemption for response fields and error bodies.

Try retrieval from your server terminal​

Prerequisites: Bash or Zsh, curl, and jq; a completed user authorization for this Resource; and a same-Project Proxy client. Set AIGW_ACCESS_TOKEN, AIGW_PROXY_CLIENT_ID, and AIGW_PROXY_CLIENT_SECRET in your server environment. The user token needs ext_token:read. These are runtime credentials, separate from the DevCLI (aigw command-line tool) management API key.

set -o pipefail
AIGW_RESOURCE_INDICATOR='https://mcp.example.com/mcp'

PROXY_TOKEN=$(curl --fail-with-body --silent --show-error \
--user "$AIGW_PROXY_CLIENT_ID:$AIGW_PROXY_CLIENT_SECRET" \
--data-urlencode 'grant_type=client_credentials' \
'https://core.api.aigw.loginid.ai/oauth2/token' | jq -er '.access_token')

# Run only after the command above succeeds and PROXY_TOKEN is nonempty.
if [ -n "$PROXY_TOKEN" ]; then
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $AIGW_ACCESS_TOKEN" \
-H "X-Proxy-Token: $PROXY_TOKEN" \
-H 'Content-Type: application/json' \
--data "$(jq -nc --arg resource "$AIGW_RESOURCE_INDICATOR" '{resource:$resource}')" \
'https://api.aigw.loginid.ai/api/credentials/token' \
| jq '{hasAccessToken: (.access_token != null), expires_at, scopes}'
fi

Replace the indicator with the exact value registered in your Resource. Expected result: hasAccessToken: true, with expiry/scopes when returned. This example displays a summary; your backend uses the returned access_token in the merchant API call. If retrieval fails, use the status and error response with Handle retrieval errors.

Project matching rule​

Same Project

The AIGW access token and proxy token must belong to the same Project. Redemption fails when the Proxy client belongs to a different Project than the user's token. Cache lookup also binds the user token to its specific login ID; a token from another sign-in cannot retrieve this login's merchant credential. X-Proxy-Token contains the token value without a Bearer prefix.

When the merchant access token is actually provisioned​

AIGW requests the merchant access token when the user completes authorization. Sign-in can succeed even if the merchant authorization server rejects that request. The stored token is bound to the user’s login, Project, and Resource; check the Resource’s Events if no token is available.

The credential redemption call then reads that cached token and refreshes it when needed. If a refresh token exists, AIGW uses it. If it is missing or rejected, AIGW removes the unrenewable cache entry and returns 410 with msgCode: reauthentication_required. Start a new user authorization; AIGW does not mint a fresh user assertion from an expired login.

Sign-in can succeed without a merchant access token

Merchant-token provisioning is best effort. A user can complete sign-in even if it fails, and the failure may only surface when the MCP/UCP server later tries to redeem the credential.

How AIGW talks to the merchant authorization server​

For the private_key_jwt configuration, AIGW sends:

The user assertion is ES256-signed using the Resource signing key. The relevant claims are:

ClaimValue
issAIGW per-resource issuer https://api.aigw.loginid.ai/<RESOURCE_ID>
subUser identifier presented to the merchant: an email from the user's sign-in provider or the AIGW pairwise subject
audMerchant authorization-server issuer configured as Issuer URL
iat, expCurrent time and configured assertion lifetime
jtiUnique UUID

The client assertion uses the merchant-AS client ID as iss and sub and the same merchant issuer as aud.

User matching fallback​

AIGW first tries each email returned by the user's sign-in provider, in order, then the AIGW pairwise subject. Each assertion contains one of these identifiers as sub. AIGW only tries the next identifier when the merchant AS returns invalid_grant with an error description containing user not found (case-insensitive). Other errors stop the attempt.

This means the merchant IAM integration needs an explicit strategy for user lookup/provisioning. See Merchant Authorization Server.

Handle retrieval errors​

StatusMeaning / next action
400Missing/malformed input or an unsupported exchange configuration; check msgCode and msg
401User/proxy authentication, user ext_token:read scope, revoked proxy client, or Project mismatch
404Wrong indicator/Project or no cached credential for this login; inspect provisioning events
410reauthentication_required: start user authorization again
500Service/downstream failure; inspect Resource Events and retry transient failures with bounded backoff

The ID token is not an acceptable substitute for the AIGW user access token. On an exchange failure, inspect the Events tab even when the user sign-in succeeded.