Skip to main content

Token endpoint

AIGW uses the core token endpoint for multiple grants:

https://core.api.aigw.loginid.ai/oauth2/token

Authorization code exchange​

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=<AUTHORIZATION_CODE>
&redirect_uri=<REGISTERED_REDIRECT_URI>
&client_id=<AGENT_CLIENT_ID>
&client_secret=<AGENT_CLIENT_SECRET>
&code_verifier=<PKCE_VERIFIER>
&resource=https%3A%2F%2Fmcp.example.com%2Fmcp

This example authenticates a client_secret_post agent. Use Basic for a client_secret_basic client, omit the secret for public none plus PKCE, or use the registered asymmetric client assertion for private_key_jwt. Validate state before exchanging the code and validate the ID token (including nonce) afterward.

Successful response​

HTTP 200 OK with Content-Type: application/json:

{
"access_token": "<AIGW_ACCESS_TOKEN>",
"token_type": "bearer",
"expires_in": 3600,
"scope": "openid ext_token:read search:read",
"id_token": "<ID_TOKEN>"
}

expires_in is the number of seconds until the access token expires; the default is 3600. Use the returned value. id_token is issued for an OpenID Connect authorization. A refresh_token can also be returned when offline access is granted. Treat token strings as credentials; their format is not an API contract.

Refresh an agent access token​

Request offline_access during authorization if your agent needs to refresh access without repeating the user authorization flow. Use the returned refresh token with the same client's registered authentication method:

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=<REFRESH_TOKEN>
&client_id=<AGENT_CLIENT_ID>
&client_secret=<AGENT_CLIENT_SECRET>

HTTP 200 OK:

{
"access_token": "<AIGW_ACCESS_TOKEN>",
"token_type": "bearer",
"expires_in": 3600,
"scope": "openid offline_access ext_token:read search:read",
"refresh_token": "<REFRESH_TOKEN>"
}

Store any replacement refresh token atomically with the new access token. If the response omits refresh_token, retain the existing one. If refresh returns invalid_grant, start a new user authorization. A Proxy token cannot refresh a user's access token.

Proxy client credentials​

POST /oauth2/token
Authorization: Basic base64(<PROXY_CLIENT_ID>:<PROXY_CLIENT_SECRET>)
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

HTTP 200 OK:

{
"access_token": "<PROXY_TOKEN>",
"token_type": "bearer",
"expires_in": 3600,
"scope": ""
}

Cache the Proxy token until shortly before the returned expiry, then obtain another with the same grant. This grant does not issue a user ID token or a refresh token.

These are different OAuth clients with different purposes: the agent client is dynamically registered; the Proxy client is created by the Project operator for the MCP/UCP server.

Response fields​

FieldAvailabilityMeaning
access_tokenSuccessful grantsCredential for the authorized operation
token_typeSuccessful grantsbearer; use Authorization: Bearer when sending the token
expires_inToken lifetime, in secondsTime from issuance until access-token expiry
scopeGranted scope informationSpace-separated scopes; may be empty for a Proxy token
id_tokenOpenID Connect grantsUser authentication result; validate it separately from the access token
refresh_tokenWhen refresh is grantedCredential for obtaining another agent access token; keep it confidential

Token, code, and assertion lifetimes​

Default lifetimes are listed below. Use the response's expires_in or the validated JWT's exp when handling an issued token.

CredentialDefault lifetimeExpiration and renewal
AIGW access token / Proxy token1 hour (3,600 seconds)Read expires_in; refresh an agent token or obtain another Proxy token before expiry
ID token1 hourValidate JWT exp, issuer, audience, signature, and nonce
Refresh token24 hoursStore replacement tokens; start authorization again on invalid_grant. Access-token expires_in does not describe refresh-token expiry
Authorization code10 minutes; single-useExchange immediately after validating the callback; restart authorization if expired or already used
Merchant-facing user or client assertion5 minutesValidate iat, exp, and the signature at the merchant authorization server; do not reuse an expired assertion
Merchant access tokenDetermined by the merchant authorization serverRead redemption response expires_at when supplied; omission does not mean the token never expires

Errors​

A rejected code or refresh token returns HTTP 400 Bad Request:

{
"error": "invalid_grant",
"error_description": "The provided authorization grant or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."
}
HTTP statuserrorAction
400invalid_requestCheck required form fields and encoding
400 or 401invalid_clientCheck the client ID, credential, and registered authentication method
400invalid_grantCheck redirect URI and PKCE verifier; obtain a new code or repeat user authorization for an expired/revoked refresh token
400unauthorized_clientUse a grant permitted for this client
400unsupported_grant_typeCheck the grant_type value
400invalid_scopeRequest only scopes allowed for the client and original grant

Branch on error, not the wording of error_description. Error responses may include additional diagnostic fields. Authentication failures using HTTP Basic can return 401 with a WWW-Authenticate header.