oauth
Covers 7 API operations in the oauth category.
| Method | Path | Description |
|---|---|---|
| GET | /.well-known/oauth-authorization-server | Authorization server metadata (RFC 8414) |
| GET | /.well-known/jwks.json | The access tokens' public keys |
| POST | /v1/oauth/authorize | Approve a connected app and mint an authorization code |
| POST | /oauth/token | Exchange a code, or refresh (RFC 6749) |
| POST | /oauth/revoke | Sign a connected app out (RFC 7009) |
| GET | /v1/oauth/grants | Connected apps |
| DELETE | /v1/oauth/grants/{sid} | Remove a connected app |
GET /.well-known/oauth-authorization-server
What a client reads before it has any credential, so it is open by definition.
authorization_endpoint points at the dashboard, not at this API: the
authorization step has to see the user's login session, which lives in the browser
(docs/studio.md §8.1). runlot_access_token_audience is not in RFC 8414 — it is here
so a resource server learns the aud it must require from the issuer rather than from
a second configured value that can disagree.
operationId oauthMetadata
| Status code | Description | Response body |
|---|---|---|
| 200 | The metadata document | object |
| 503 | Connected-app sign-in is not configured on this deployment | Error |
GET /.well-known/jwks.json
Every non-retired signing key. Two are published during a rotation, which is the whole reason this is a set: a verifier that cached one key would refuse tokens minted with the other. Cacheable for a minute, and no longer — a stale copy refuses fresh tokens.
operationId oauthJwks
| Status code | Description | Response body |
|---|---|---|
| 200 | The key set | object |
POST /v1/oauth/authorize
Called by the dashboard's /oauth/authorize screen with the user's login session.
A personal access token is refused whatever its scopes: a credential must never be
able to widen itself into a longer-lived one.
The parameters carry OAuth's own names rather than this document's camelCase, because the screen forwards the query string it was handed.
operationId oauthAuthorize
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 200 | Approved. The browser is sent to redirect. | object |
| 400 | — | — |
| 401 | — | — |
POST /oauth/token
Form-encoded, not JSON — RFC 6749 §4.1.3, and what every client library sends.
The failures are RFC 6749 §5.2's body, not this document's error envelope, because these two endpoints are read by generic OAuth clients that cannot parse ours.
Refresh tokens rotate: using one invalidates it and returns the next. Rate limited per
client and per address (429).
operationId oauthToken
Request body: application/x-www-form-urlencoded · object
| Status code | Description | Response body |
|---|---|---|
| 200 | A new access token, and the next refresh token | OAuthTokenResponse |
| 400 | RFC 6749 §5.2 | OAuthError |
| 429 | Too many attempts from this client or this address | OAuthError |
| 503 | Connected-app sign-in is not configured on this deployment | OAuthError |
POST /oauth/revoke
Form-encoded. It answers 200 for a token it does not know — RFC 7009 §2.2 requires it, and the reason is that any other answer turns the endpoint into an oracle for which tokens exist.
Revoking a refresh token revokes the whole grant, not one rotation generation:
"sign out in Studio" means the device is gone from Connected apps too (docs/studio.md
§8.4). Rate limited per client and per address (429).
operationId oauthRevoke
Request body: application/x-www-form-urlencoded · object
| Status code | Description | Response body |
|---|---|---|
| 200 | Revoked, or the token was unknown — the two are deliberately the same answer | — |
| 400 | RFC 6749 §5.2 | OAuthError |
| 429 | Too many attempts from this client or this address | OAuthError |
GET /v1/oauth/grants
What can reach this account right now (docs/studio.md §8.4). Revoked grants are not listed: a list that keeps dead rows makes the answer a filter the reader has to apply.
Session only, for POST /v1/oauth/authorize's reason.
operationId listOAuthGrants
| Status code | Description | Response body |
|---|---|---|
| 200 | The grants | object |
| 401 | — | — |
DELETE /v1/oauth/grants/{sid}
Its refresh tokens die with it, its access token dies on the next request through the
sid check, and the revocation reaches the Studio service through cp-core's feed — so
a lent model drops at once rather than within the access token's fifteen minutes.
A grant that is not this user's is a 404, not a 403: telling a caller that somebody else's grant id exists is a probe for grant ids.
operationId revokeOAuthGrant
| Status code | Description | Response body |
|---|---|---|
| 204 | Removed | — |
| 401 | — | — |
| 404 | — | — |