OAuth2 API Reference
The orbit-oauth2 authorization server runs on port 3003. Public endpoints follow OAuth 2.0 / RFC standards.
Internal endpoints are loopback-restricted and require Authorization: Bearer <ORBIT_INTERNAL_SECRET>.
Discovery & JWKS
| Method | Path | Description |
|---|---|---|
GET | /.well-known/oauth-authorization-server | RFC 8414 server metadata. Issuer, endpoints, supported grant types, scopes, code challenge methods. |
GET | /.well-known/jwks.json | JSON Web Key Set. Active and retired signing public keys. |
GET | /oauth2/certificates | Permanent alias for JWKS (backwards compatibility). |
Authorization
GET /oauth2/authorizeStarts the authorization code + PKCE flow. Browser redirect endpoint.
Query Parameters
| Param | Required | Description |
|---|---|---|
client_id | Yes | Registered client UUID |
response_type | Yes | Must be code |
redirect_uri | Yes | Must match a registered URI |
code_challenge | Yes | S256 PKCE challenge |
code_challenge_method | Yes | Must be S256 |
scope | No | Space-separated scopes |
state | No | Opaque state for CSRF protection |
On success, creates a pending authorization challenge (10-min TTL) and redirects 302 to the client's
consent_uri with ?challenge={id}.
Token
POST /oauth2/tokenToken endpoint. Request body is application/x-www-form-urlencoded. Dispatches by grant_type.
grant_type=authorization_code
| Field | Required | Description |
|---|---|---|
code | Yes | Authorization code |
redirect_uri | Yes | Must match the authorize request |
code_verifier | Yes | PKCE verifier (43-128 unreserved chars) |
client_id | Public clients | In body for public; via Basic auth for confidential |
Returns: { access_token, token_type: "Bearer", expires_in: 3600, scope } plus refresh_token if offline_access was granted.
grant_type=client_credentials
Confidential clients only via HTTP Basic auth. Optional: scope. Returns JWT with sub = client_id. No refresh token.
grant_type=refresh_token
| Field | Required | Description |
|---|---|---|
refresh_token | Yes | Current refresh token |
client_id | Public clients | Via body or Basic auth |
Token rotation: old refresh token revoked, new one issued. Theft detection: replay of a revoked token revokes all tokens for that subject+client.
curl Example
# Authorization code exchange
curl -X POST https://oauth.example.com/oauth2/token \
-d "grant_type=authorization_code" \
-d "code=${AUTH_CODE}" \
-d "redirect_uri=https://app.example.com/callback" \
-d "code_verifier=${PKCE_VERIFIER}" \
-d "client_id=${CLIENT_ID}"
# Client credentials
curl -X POST https://oauth.example.com/oauth2/token \
-u "${CLIENT_ID}:${CLIENT_SECRET}" \
-d "grant_type=client_credentials" \
-d "scope=read write"
Token Revocation
POST /oauth2/revokeRFC 7009. Form-encoded body.
| Field | Required | Description |
|---|---|---|
token | Yes | Token to revoke (access or refresh) |
client_id | Public clients | Via body or Basic auth |
Always returns 200 (silent on invalid/unknown tokens per RFC).
Dynamic Client Registration
POST /oauth2/registerRFC 7591. Open registration (no auth required).
Request Body
| Field | Required | Description |
|---|---|---|
client_name | Yes | Human-readable client name |
client_type | Yes | "confidential" or "public" |
redirect_uris | Yes | Array of allowed redirect URIs |
consent_uri | Yes | URL of the CAS consent page |
consent_jwk | Yes | Public JWK for consent signature verification |
scopes | No | Allowed scopes (default: ["offline_access"]) |
Returns 201 with client details. Confidential clients also receive client_secret (shown once).
CAS Integration
These endpoints are used by the Central Authentication Service (consent provider) to interact with pending authorization challenges.
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /oauth2/challenges/:id | None* | Get challenge details: client_id, client_name, scope, state. |
POST | /oauth2/consent | Signature | Submit consent decision. Signed with client's consent_jwk. |
GET | /oauth2/grants | Signature | Check prior consent. Returns scope diff (granted/requested/added/removed/unchanged). |
* Challenge ID serves as the credential (unguessable UUID).
The CAS signs each consent submission with the private key corresponding to the client's consent_jwk.
Canonical string: {challenge_id}:{subject}:{scope}:{approved}:{timestamp}:{sha512(claims)}
Supported algorithms: Ed25519 (recommended), EC P-256/P-384/P-521. No RSA.
Replay protection: Timestamp must be within ±60 seconds of server time.
Internal API
Loopback-restricted. Requires Authorization: Bearer <ORBIT_INTERNAL_SECRET>.
Used by orbit-service to proxy OAuth2 client management.
Key Management
| Method | Path | Description |
|---|---|---|
GET | /internal/oauth2/keys | List signing keys. |
POST | /internal/oauth2/keys/rotate | Generate new EC P-521 keypair. Returns 201. |
POST | /internal/oauth2/keys/:kid/retire | Retire key (stays in JWKS). Returns 204. |
Client Management
| Method | Path | Description |
|---|---|---|
GET | /internal/oauth2/clients | List clients. Query: cursor?, limit?. |
POST | /internal/oauth2/clients | Create client. |
GET | /internal/oauth2/clients/:id | Get client. |
PATCH | /internal/oauth2/clients/:id | Update. client_type is immutable. |
DELETE | /internal/oauth2/clients/:id | Delete (cascades). Returns 204. |
POST | /internal/oauth2/clients/:id/rotate-secret | Rotate secret (confidential only). |
POST | /internal/oauth2/clients/:id/revoke | Revoke all tokens. Returns 204. |
GET | /internal/oauth2/clients/:id/grants | List grants. |
DELETE | /internal/oauth2/clients/:id/grants/:subject | Revoke grant. Returns 204. |