Issue an access token
POST/oauth/token
Exchanges a signed client assertion for an opaque access token.
The assertion is a JWT signed with your private key, carrying:
| Claim | Value |
|---|---|
iss, sub | Your client id (oc_…), both |
aud | This endpoint's absolute URL for the environment you are calling |
exp | At most five minutes ahead |
jti | A value unique among your own assertions; each is redeemable once |
Signed with ES256 or RS256. Every registered key must carry a
kid once a client holds more than one; the JWT header's own kid
picks which one verifies the assertion, and omitting it tries them
all. Send it anyway — it makes a rotation legible in your own logs —
but a refusal will not name the key: every pre-verification failure,
clock skew included, returns the same deliberately generic
invalid_client so that an unauthenticated caller cannot learn
whether a client id is real.
Omit scope to receive every scope the client holds. Name a scope the
client does not hold and the whole request is refused.
This endpoint answers in RFC 6749's error shape, not the envelope
the rest of the API uses. Failures are \{"error": "…", "error_description": "…"\}, flat, because that is what OAuth client
libraries parse. Nothing here is retryable without changing the
request — a fresh assertion, a corrected audience, or a scope the
client actually holds.
Request
Responses
- 200
- 400
- 401
- 500
Token issued. Not cacheable.
Response Headers
Always no-store.
Malformed request, unsupported grant, an assertion already redeemed, or a scope the client does not hold.
The client is unknown or revoked, the assertion did not verify, it was signed for another environment, or the source address is not permitted.
An unexpected failure on our side, unrelated to the request.
No other operation in this document declares a 500 — everywhere
else, an unexpected failure still returns the site-wide
ErrorResponse envelope, so leaving it undocumented is safe: a
reader's assumption carries over correctly. It does not carry
over here. This endpoint's failures, including this one, are
RFC 6749's flat shape, not that envelope, and a client that
assumes otherwise parses the wrong thing at exactly the moment it
most needs a useful log line — so this one 500 is spelled out.