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

MethodPathDescription
GET/.well-known/oauth-authorization-serverRFC 8414 server metadata. Issuer, endpoints, supported grant types, scopes, code challenge methods.
GET/.well-known/jwks.jsonJSON Web Key Set. Active and retired signing public keys.
GET/oauth2/certificatesPermanent alias for JWKS (backwards compatibility).

Authorization

GET /oauth2/authorize

Starts the authorization code + PKCE flow. Browser redirect endpoint.

Query Parameters
ParamRequiredDescription
client_idYesRegistered client UUID
response_typeYesMust be code
redirect_uriYesMust match a registered URI
code_challengeYesS256 PKCE challenge
code_challenge_methodYesMust be S256
scopeNoSpace-separated scopes
stateNoOpaque 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/token

Token endpoint. Request body is application/x-www-form-urlencoded. Dispatches by grant_type.

grant_type=authorization_code
FieldRequiredDescription
codeYesAuthorization code
redirect_uriYesMust match the authorize request
code_verifierYesPKCE verifier (43-128 unreserved chars)
client_idPublic clientsIn 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
FieldRequiredDescription
refresh_tokenYesCurrent refresh token
client_idPublic clientsVia 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/revoke

RFC 7009. Form-encoded body.

FieldRequiredDescription
tokenYesToken to revoke (access or refresh)
client_idPublic clientsVia body or Basic auth

Always returns 200 (silent on invalid/unknown tokens per RFC).

Dynamic Client Registration

POST /oauth2/register

RFC 7591. Open registration (no auth required).

Request Body
FieldRequiredDescription
client_nameYesHuman-readable client name
client_typeYes"confidential" or "public"
redirect_urisYesArray of allowed redirect URIs
consent_uriYesURL of the CAS consent page
consent_jwkYesPublic JWK for consent signature verification
scopesNoAllowed 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.

MethodPathAuthDescription
GET/oauth2/challenges/:idNone*Get challenge details: client_id, client_name, scope, state.
POST/oauth2/consentSignatureSubmit consent decision. Signed with client's consent_jwk.
GET/oauth2/grantsSignatureCheck prior consent. Returns scope diff (granted/requested/added/removed/unchanged).

* Challenge ID serves as the credential (unguessable UUID).

Consent Signature

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

MethodPathDescription
GET/internal/oauth2/keysList signing keys.
POST/internal/oauth2/keys/rotateGenerate new EC P-521 keypair. Returns 201.
POST/internal/oauth2/keys/:kid/retireRetire key (stays in JWKS). Returns 204.

Client Management

MethodPathDescription
GET/internal/oauth2/clientsList clients. Query: cursor?, limit?.
POST/internal/oauth2/clientsCreate client.
GET/internal/oauth2/clients/:idGet client.
PATCH/internal/oauth2/clients/:idUpdate. client_type is immutable.
DELETE/internal/oauth2/clients/:idDelete (cascades). Returns 204.
POST/internal/oauth2/clients/:id/rotate-secretRotate secret (confidential only).
POST/internal/oauth2/clients/:id/revokeRevoke all tokens. Returns 204.
GET/internal/oauth2/clients/:id/grantsList grants.
DELETE/internal/oauth2/clients/:id/grants/:subjectRevoke grant. Returns 204.