OAuth 2.0 & OpenID Connect
LumoAuth implements OAuth 2.0 and OpenID Connect (OIDC) as its core authorization and authentication framework. RFC 6749 — OAuth 2.0 Authorization Framework defines the authorize and token endpoints and the standard grant types (authorization code, client credentials, refresh token, etc.); OIDC adds an identity layer on top with an id_token and userinfo endpoint. This guide covers grant types, token management, OIDC features, and protocol extensions.
Supported Grant Types
| Grant Type | Use Case | RFC |
|---|---|---|
| Authorization Code | Web apps, SPAs (with PKCE) | RFC 6749 |
| Authorization Code + PKCE | Public clients (SPAs, mobile) | RFC 7636 |
| Client Credentials | Machine-to-machine | RFC 6749 |
| Refresh Token | Renew expired access tokens | RFC 6749 |
| Device Authorization | CLI tools, smart TVs, IoT | RFC 8628 |
| CIBA | Decoupled authentication (call center, POS) | OIDC CIBA |
Authorization Code Flow
The most common flow for web applications:
1. App redirects user to:
/orgs/{orgId}/api/v1/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://your-app.com/callback
&scope=openid profile email
&state=random_state
2. User authenticates (login page)
3. LumoAuth redirects back with authorization code:
https://your-app.com/callback?code=AUTH_CODE&state=random_state
4. App exchanges code for tokens:
POST /orgs/{orgId}/api/v1/oauth/token
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https://your-app.com/callback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
With PKCE (for Public Clients)
Add PKCE parameters for SPAs and mobile apps:
Step 1: Generate code_verifier and code_challenge
Step 2: Include in authorization request:
&code_challenge=CHALLENGE
&code_challenge_method=S256
Step 3: Include in token request:
&code_verifier=VERIFIER
Client Credentials Flow
For machine-to-machine authentication (no user involved):
curl -X POST https://your-domain.com/orgs/{orgId}/api/v1/oauth/token \
-d grant_type=client_credentials \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d scope="api:read api:write"
Refresh Token Flow
Exchange a refresh token for a new access token:
curl -X POST https://your-domain.com/orgs/{orgId}/api/v1/oauth/token \
-d grant_type=refresh_token \
-d refresh_token=YOUR_REFRESH_TOKEN \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET
OIDC Features
Discovery
Every organization exposes an OIDC discovery document:
GET /orgs/{orgId}/.well-known/openid-configuration
Returns endpoints, supported scopes, signing algorithms, and more.
ID Tokens
ID tokens are JWTs containing user identity claims:
{
"iss": "https://your-domain.com/orgs/acme-corp",
"sub": "user-uuid",
"aud": "client-id",
"exp": 1706403600,
"iat": 1706400000,
"nonce": "random-nonce",
"email": "alice@acme.com",
"name": "Alice Smith",
"email_verified": true
}
UserInfo Endpoint
curl https://your-domain.com/orgs/{orgId}/api/v1/oauth/userinfo \
-H "Authorization: Bearer {access_token}"
Standard Scopes
| Scope | Claims Included |
|---|---|
openid | sub |
profile | name, given_name, family_name, picture |
email | email, email_verified |
phone | phone_number, phone_number_verified |
roles | roles array |
permissions | permissions array |
JWKS Endpoint
JWKS (JSON Web Key Set, RFC 7517) is a JSON document listing the public keys a service uses to sign its JWTs. Clients fetch it to verify access and ID tokens.
GET /orgs/{orgId}/.well-known/jwks.json
Advanced Protocol Extensions
DPoP (Demonstration of Proof-of-Possession) — RFC 9449
RFC 9449 — DPoP binds an access token to a key pair held by the client. Every API call must include a fresh signed proof, so a stolen bearer token alone cannot be replayed by an attacker.
# Include DPoP proof header in token request
curl -X POST https://your-domain.com/orgs/{orgId}/api/v1/oauth/token \
-H "DPoP: eyJ..." \
-d grant_type=authorization_code \
-d code=AUTH_CODE \
-d client_id=YOUR_CLIENT_ID
The resulting token is bound to the DPoP key and can only be used with a matching DPoP proof.
PAR (Pushed Authorization Requests) — RFC 9126
RFC 9126 — Pushed Authorization Requests lets the client POST the authorization parameters to the server first and then redirect the user with a short opaque request_uri. This keeps sensitive parameters out of the browser address bar and front channel.
# Push authorization request
curl -X POST https://your-domain.com/orgs/{orgId}/api/v1/oauth/par \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d response_type=code \
-d redirect_uri=https://your-app.com/callback \
-d scope="openid profile"
# Response: {"request_uri": "urn:ietf:params:oauth:request_uri:...", "expires_in": 60}
# Redirect user with the request_uri
/orgs/{orgId}/api/v1/oauth/authorize?client_id=YOUR_CLIENT_ID&request_uri=urn:ietf:params:oauth:request_uri:...
RAR (Rich Authorization Requests) — RFC 9396
RFC 9396 — Rich Authorization Requests extends OAuth with a structured authorization_details parameter so the client can request fine-grained, typed authorization (for example a specific payment amount or a specific set of account operations) instead of only flat scope strings.
{
"authorization_details": [
{
"type": "payment_initiation",
"instructedAmount": {"currency": "EUR", "amount": "123.50"},
"creditorName": "Merchant Inc.",
"creditorAccount": {"iban": "DE02..."}
}
]
}
Dynamic Client Registration — RFC 7591
RFC 7591 — OAuth 2.0 Dynamic Client Registration defines a JSON API for registering OAuth clients at runtime instead of through the admin portal. Paired with RFC 8414 — OAuth 2.0 Authorization Server Metadata, clients can discover endpoints and then self-register.
curl -X POST https://your-domain.com/orgs/{orgId}/api/v1/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My App",
"redirect_uris": ["https://my-app.com/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_post"
}'
CIBA (Client-Initiated Backchannel Authentication)
Initiate authentication from a backend service:
curl -X POST https://your-domain.com/orgs/{orgId}/api/v1/oauth/bc-authorize \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d scope="openid" \
-d login_hint="alice@acme.com" \
-d binding_message="Approve login from call center"
The user receives a push notification or out-of-band prompt to approve.
Token Formats
| Token | Format | Description |
|---|---|---|
| Access Token | JWT (RFC 9068) | RFC 7519 — JSON Web Token format; verifiable without a server call using the public keys at the JWKS endpoint |
| Refresh Token | Opaque | Must be exchanged at the token endpoint |
| ID Token | JWT | OIDC identity claims (also a JWT per RFC 7519) |
| Authorization Code | Opaque | Short-lived, single-use |
Token Revocation
RFC 7009 — OAuth 2.0 Token Revocation defines this endpoint. Clients call it to invalidate an access or refresh token immediately (for example on logout or when a token is compromised).
curl -X POST https://your-domain.com/orgs/{orgId}/api/v1/oauth/revoke \
-d token=TOKEN_TO_REVOKE \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET
Related Guides
- Applications Overview - Register and manage applications
- Device Flow - Device Authorization grant
- Signing Keys - JWT signing key management
- SAML Applications - SAML 2.0 integration