Skip to main content
POST
Obtain short-lived MCP access tokens using a public client’s S256 authorization code or its current refresh token.

Authentication

No HTTP client authentication. Send client_id in the URL-encoded body. Any Authorization header, client_secret, or client_assertion is rejected.

Request body

Request examples

Follow the documented encoding and authentication for this route. The action API’s envelope and idempotency rules apply only to action invocations.

Response

An opaque Bearer access token, its remaining lifetime in seconds, granted scopes, and a refresh token when the client registered refresh_token. expires_in is at most 900 and may be smaller near grant expiry.
HTTP 200

Response headers

Operation notes

  • Recognized scalar parameters must be supplied once as nonempty strings without ASCII control characters or DEL. Repeated query/form fields decode to arrays and are rejected when read as scalars.
  • Use URL-encoded form data, such as curl —data-urlencode per field. A JSON token body is rejected with invalid_request.
  • The resource audience is required for both grant types and must exactly match the MCP URL of the environment that issued the code or refresh token.
  • Authorization-code exchange requires the original client_id, exact redirect_uri, and matching S256 code_verifier. Codes expire after 2 minutes and are single-use.
  • The token endpoint rejects every supplied Authorization header, including Basic and Bearer, plus any client_secret or client_assertion body field.
  • Access tokens last at most 15 minutes. With refresh_token registered, the connection and refresh family expire 30 days after the user approved it; rotation does not extend that deadline.
  • Whether refresh_token is returned depends on the registered grant types. It does not depend on including offline_access in the authorization request. Returned scope appends offline_access whenever a refresh token is returned.
  • To renew, send grant_type=refresh_token with client_id, the current refresh_token, resource, and optionally a narrowed scope. Atomically replace the stored refresh token with the new value.
  • Reusing a consumed authorization code or rotated refresh token revokes the whole connection, including all of its access tokens. Do not concurrently redeem the same code or refresh token.
  • Refresh requests never add permissions. With an explicit scope, only the requested product and identity permissions are retained; offline_access does not preserve omitted product permissions.
  • Tokens are bound to the granting user, client, resource audience, current team ownership, and active paid access. A revoked grant or changed ownership requires reconnecting.
  • The public token limit is 60 requests per minute per client IP, shared across workers. URL-encoded bodies are limited to 32 KiB.
  • OAuth failures return error and error_description. Body-parser failures can be returned earlier in the integration parser’s error form.
  • openid and email are identity permissions, separate from product permissions, and are accepted only when advertised. email requires openid. During initial authorization, a request containing only identity scopes uses the default product permissions shown on the consent screen.
  • The client_id returned by dynamic registration, or the exact public HTTPS URL of the client metadata document.
  • When openid is granted, authorization-code exchange also returns an RS256-signed id_token. Validate its signature, issuer, audience, expiry, and nonce when supplied. Granted identity scopes appear in the token response scope; refresh responses do not issue a new id_token.
  • If OpenID Connect becomes unavailable, refreshing without scope keeps the product permissions and removes identity permissions. Explicitly requesting unavailable identity scopes returns invalid_scope.
  • If the account was deleted or disabled, the token endpoint returns invalid_grant with HTTP 400.

Errors