OIDC & OAuth 2.0 Compliance
Complete reference of OAuth 2.0 and OpenID Connect standards implemented by AuthPI.
Last updated 2026-07-19
AuthPI implements OAuth 2.0 and OpenID Connect (OIDC) following the relevant RFCs and specifications. This document details which standards are supported, how they’re implemented, and any deviations or limitations.
Standards Overview
| Standard | Status | Notes |
|---|---|---|
| OAuth 2.0 (RFC 6749) | Partial | Authorization code and refresh token grants |
| OAuth 2.0 Bearer Tokens (RFC 6750) | Full | |
| PKCE (RFC 7636) | Full | S256 only, required for public clients |
| Token Introspection (RFC 7662) | Full | |
| Token Revocation (RFC 7009) | Full | |
| JWT Access Tokens (RFC 9068) | Full | |
| Resource Indicators (RFC 8707) | Partial | Authorization-code and refresh grants bind repeated resource values; client_credentials supports one resource |
| Client ID Metadata Documents (IETF draft) | Opt-in | Public authorization-code clients; disabled by default per issuer |
| OpenID Connect Core 1.0 | Full | |
| OpenID Connect Discovery 1.0 | Full | |
| OpenID Connect Session Management 1.0 | Partial | Front-channel and back-channel logout |
OAuth 2.0 (RFC 6749)
Supported Grant Types
Authorization Code Grant (RFC 6749 Section 4.1)
The primary grant type for web applications and native apps. The flow works as follows:
- Client redirects user to
/authorizewithresponse_type=code - User authenticates and consents
- AuthPI redirects back with an authorization code
- Client exchanges code for tokens at
/token
GET /authorize?
response_type=code&
client_id=c_xxx&
redirect_uri=https://app.example.com/callback&
scope=openid%20profile%20email&
state=abc123
Refresh Token Grant (RFC 6749 Section 6)
Exchange a refresh token for new access and refresh tokens:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
refresh_token=eyJ...&
client_id=c_xxx&
scope=openid profile
The optional scope parameter may narrow the granted scope for the issued access token (RFC 6749 §6) — it must be a subset of the original grant, or the request fails with invalid_scope. Omit it to receive the full grant. The token response includes the effective scope, and the rotated refresh token always retains the complete original grant, so narrowing one refresh does not shrink later ones.
AuthPI implements refresh token rotation—each refresh returns a new refresh token, and the old one is invalidated. This improves security by limiting the window for token theft. Granted scopes and organization memberships are re-applied on every refresh: scopes from the grant of record, memberships fresh from the directory.
If the original authorization request used org=org_..., refresh keeps that same selected-organization restriction. The refresh request itself cannot add or change org.
Client Credentials Grant (RFC 6749 Section 4.4)
Machine-to-machine authentication with no user involved:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&
scope=read:data
The client authenticates via HTTP Basic (client_secret_basic) or client_id + client_secret form parameters (client_secret_post).
- Available to M2M clients (
application_type: "m2m", confidential, withclient_credentialsin theirgrant_types) and to agents (agt_...identities authenticating with a secret verifier). - The response contains an access token only — no refresh token and no ID token. The
openidscope is ignored for this grant. - If no
scopeis requested, the token carries the client’s (or agent’s) full allowed scope set. Requesting a scope outside the allowed set fails withinvalid_scope. - The optional
resourceparameter sets the token’saudclaim; otherwise the audience defaults to the client id. - Token lifetime: the client’s
default_access_token_age(default 30 minutes). Agent tokens are fixed at 5 minutes so scope changes propagate quickly.
Note: the client credentials grant issues OAuth access tokens for calling your own APIs. To call the AuthPI Core (admin) API from a backend, use org API keys instead.
Not Supported
The following grant types are not implemented:
- Implicit Grant (RFC 6749 Section 4.2): Deprecated; use authorization code with PKCE
- Resource Owner Password (RFC 6749 Section 4.3): Not recommended due to security concerns
- Device Authorization (RFC 8628): Not currently supported
Client ID Metadata Documents
Client ID Metadata Documents (CIMD) let a public OAuth client use the exact HTTPS URL of a JSON metadata document as its client_id. AuthPI fetches and validates that document instead of looking up a stored Client resource. CIMD does not dynamically register the client or create a Client resource; see Registered Clients, CIMD, and Dynamic Registration for when to use each model.
CIMD is disabled by default. Enable it for an issuer through its settings:
{
"settings": {
"security": {
"openid_policy": {
"client_id_metadata_document": {
"enabled": true,
"organization_policy": "none"
}
}
}
}
}
organization_policy defaults to none. Set it to selected to allow only an explicitly selected active organization membership, or all to apply the issuer’s existing all-memberships behavior. When CIMD is disabled, URL-shaped client IDs are rejected.
Client ID URL requirements
The client_id URL must:
- Use HTTPS and be no more than 1,000 characters.
- Have a non-root path.
- Have no username, password, fragment, IP-literal or local hostname, or
./..path segment.
Ports and query strings are allowed. They are identity-significant: AuthPI uses the exact URL string for document identity, caching, and consent, without normalizing it.
Supported metadata
AuthPI reads this metadata subset. Additional non-secret properties, such as client_uri and logo_uri, are accepted but ignored:
| Field | Requirement |
|---|---|
client_id | Required. Must exactly equal the URL used in the authorization request. |
client_name | Required, non-empty, at most 200 characters. |
redirect_uris | Required, with 1–100 entries. Every entry must satisfy the redirect policy below. |
token_endpoint_auth_method | Required and must be none. CIMD clients cannot use a client secret. |
grant_types | Optional; defaults to ["authorization_code"]. May also include refresh_token. |
response_types | Optional; defaults to ["code"]. No other response type is accepted. |
scope | Optional space-separated scope list, at most 1,000 characters. It narrows the scopes the client may request. |
id_token_signed_response_alg | Optional; EdDSA, ES256, or RS256. |
CIMD clients are always public authorization-code clients and must use S256 PKCE. Secret-bearing metadata, including client_secret, client_secret_expires_at, and registration_access_token, is rejected.
{
"client_id": "https://mcp-client.example.com/oauth/client-metadata.json",
"client_name": "Example MCP client",
"redirect_uris": [
"https://mcp-client.example.com/oauth/callback",
"http://127.0.0.1:6274/callback"
],
"token_endpoint_auth_method": "none",
"scope": "openid profile"
}
This example uses the omitted-field defaults for authorization code and code. To allow refresh tokens, add "grant_types": ["authorization_code", "refresh_token"]. The offline_access scope is valid only when refresh-token support is effective for both the document and issuer.
Every redirect URI in the document must be either:
- An absolute HTTPS URL, or
- An HTTP URL whose hostname is exactly
localhost,127.0.0.1, or[::1].
Credentials, fragments, malformed URLs, other HTTP hosts, and custom schemes such as javascript: or native-app schemes are rejected. The redirect_uri in the authorization request must exactly match one of the validated document values, including its scheme, host, port, path, and query.
Fetching and caching
AuthPI fetches metadata only after validating the user’s AuthPI session, and connections are restricted to public network addresses. The fetch uses a five-second timeout, does not follow redirects, requires HTTP 200 with application/json or application/*+json, and limits the response body to 5 KiB. AuthPI does not fetch or render URLs referenced by metadata fields such as logos, policies, terms, or JWKS.
Validated documents are cached according to shared-cache Cache-Control semantics, for at most one hour. s-maxage takes precedence over max-age; without explicit freshness, the cache lifetime is five minutes. no-store, no-cache, private, zero freshness, and effective lifetimes below 60 seconds prevent caching; failed or invalid responses are never cached.
Authorization display
CIMD authorization always presents a confirmation screen showing the client name, the client-ID hostname, and the requested redirect hostname, including a non-default port. AuthPI warns when the selected redirect uses a loopback address and displays a stronger warning when every redirect in the metadata document is loopback-only. Treat a localhost callback as belonging to whichever local process is listening on that port, not as proof of the client’s identity.
PKCE (RFC 7636)
Proof Key for Code Exchange prevents authorization code interception attacks. AuthPI fully implements PKCE with the following behavior:
Requirements
| Client Type | PKCE Requirement |
|---|---|
| Public clients (SPAs, native apps) | Required |
| Confidential clients | Optional but recommended |
Supported Methods
Only S256 is supported. The plain method is rejected for security reasons.
// Generate code verifier (43-128 characters, URL-safe)
const verifier = generateRandomString(64);
// Generate code challenge
const challenge = base64url(sha256(verifier));
// Authorization request
GET /authorize?
...&
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
code_challenge_method=S256
// Token request includes verifier
POST /token
...&
code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Error Handling
| Scenario | Error |
|---|---|
Public client without code_challenge | invalid_request |
code_challenge_method=plain | invalid_request |
Invalid code_verifier at token exchange | invalid_grant |
Missing code_verifier at token exchange | invalid_grant |
Token Introspection (RFC 7662)
The introspection endpoint allows resource servers to validate tokens and retrieve their metadata.
Endpoint: POST /{issuer_id}/introspect
Request
POST /introspect
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)
token=eyJ...&
token_type_hint=access_token
The token_type_hint parameter is optional but helps AuthPI validate the token more efficiently. Accepted values: access_token, refresh_token.
Response (Active Token)
{
"active": true,
"scope": "openid profile email",
"client_id": "c_xxx",
"token_type": "Bearer",
"sub": "usr_xxx",
"aud": "c_xxx",
"iat": 1705330953,
"exp": 1705332753,
"iss": "https://idp.authpi.com/i_xxx",
"jti": "tok_xxx",
"sid": "ses_xxx",
"username": "user@example.com"
}
Response (Inactive Token)
{
"active": false
}
A token is inactive if it’s expired, revoked, malformed, or issued by a different issuer.
Access vs Refresh Token Introspection
Access tokens are validated by checking:
- JWT signature validity
- Expiration time
- Revocation status in the revocation list
Refresh tokens are validated by checking:
- JWT signature validity
- Session binding (must have valid
sid) - Token rotation (JTI must match current token)
Token Revocation (RFC 7009)
Revoke tokens when users log out or when tokens may be compromised.
Endpoint: POST /{issuer_id}/revoke
Request
POST /revoke
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)
token=eyJ...&
token_type_hint=refresh_token
Response
The endpoint always returns 200 OK regardless of whether the token was valid or already revoked. This prevents information leakage about token validity.
Revocation Behavior
Refresh tokens: Revoked via the session manager. The token’s JTI is marked as revoked, and subsequent uses of the refresh token fail.
Access tokens: Added to a revocation list with a TTL matching the token’s remaining lifetime. Resource servers should introspect tokens to check revocation status.
JWT Access Tokens (RFC 9068)
AuthPI issues access tokens as JWTs following RFC 9068.
Header
{
"alg": "ES256",
"typ": "at+jwt",
"kid": "key_xxx"
}
Payload
{
"iss": "https://idp.authpi.com/i_xxx",
"sub": "usr_xxx",
"aud": "c_xxx",
"exp": 1705332753,
"iat": 1705330953,
"nbf": 1705330953,
"jti": "tok_xxx",
"client_id": "c_xxx",
"sid": "ses_xxx",
"scope": "openid profile email",
"auth_time": 1705330900
}
Supported Signing Algorithms
| Algorithm | Description |
|---|---|
| ES256 | ECDSA with P-256 curve (default) |
| RS256 | RSA with SHA-256 |
| EdDSA | Edwards-curve DSA |
The algorithm is configurable per client via settings.openid.response_signature_alg.
Resource Indicators (RFC 8707)
The OAuth resource parameter binds an authorization grant and its access tokens to the protected resource that will consume them. For authorization-code and refresh grants, send one form parameter per resource; do not combine several resource identifiers into a comma- or space-separated value.
GET /{issuer_id}/authorize?response_type=code
&client_id=c_xxx
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&scope=read%3Areports
&state=abc123
&resource=https%3A%2F%2Fapi.example.com%2Freports
&resource=https%3A%2F%2Fapi.example.com%2Fexports
Repeat the resources at authorization-code exchange to select the full authorized set or a subset:
POST /{issuer_id}/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=...&
client_id=c_xxx&
redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&
code_verifier=...&
resource=https%3A%2F%2Fapi.example.com%2Freports&
resource=https%3A%2F%2Fapi.example.com%2Fexports
The token request cannot introduce a resource that was absent from the authorization request. When resource indicators are optional and the code exchange omits resource, AuthPI selects the full set authorized by the original request.
A refresh request may select any subset of the immutable resource ceiling established by the original authorization request, including resources that were not selected at code exchange. Under an optional policy, omitting resource retains the session’s most recently selected set. A required policy rejects omission. Refresh rotation updates only that current selection; it never changes the original ceiling, so a later refresh may choose a different subset but can never add a new resource.
POST /{issuer_id}/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
refresh_token=...&
client_id=c_xxx&
resource=https%3A%2F%2Fapi.example.com%2Freports
One selected resource produces a string aud claim. Multiple selected resources produce an aud array. Array order has no meaning; resource servers must check membership rather than position. ID tokens and refresh tokens continue to use the client ID as their audience. See Token Claims for the complete claim rules.
This layered RFC 8707 policy applies to authorization-code and refresh-token flows. The client_credentials grant keeps its existing behavior: it accepts at most one resource string as the access-token audience, does not consult resource_indicators or allowed_resources, and reports malformed values as invalid_request rather than invalid_target.
Resource identifier rules
Each resource identifier must be a non-empty RFC 3986 absolute URI of at most 1,000 characters. It must use ASCII URI characters and valid percent escapes, with no whitespace, control characters, backslashes, or fragment, including an empty trailing #. One request may contain at most ten resource values. AuthPI preserves and compares the exact string—it does not normalize scheme or host casing, add or remove a trailing slash, decode percent escapes, or discard a query string. For example, these are different resources:
https://api.example.com/reportshttps://API.example.com/reportshttps://api.example.com/reports/https://api.example.com/reports?region=eu
Exact duplicate values collapse to one entry. Distinct values form a set for authorization checks, so request order is not authorization-significant and consumers must not depend on audience-array order.
Issuer and client policy
Resource authorization is layered. The issuer defines the available resources and the scopes valid for each one under settings.security.openid_policy.resource_indicators:
{
"settings": {
"security": {
"openid_policy": {
"resource_indicators": {
"required": false,
"allow_multiple": true,
"resources": [
{
"resource": "https://api.example.com/reports",
"scopes": ["read:reports"]
},
{
"resource": "https://api.example.com/exports",
"scopes": ["read:reports"]
}
]
}
}
}
}
}
resources accepts at most 100 unique entries, with at most 100 scopes on each entry. required defaults to false; when true, the authorization request and every authorization-code or refresh-token request must explicitly select a resource. Omission never falls back to the grant or session selection while this flag is enabled. allow_multiple defaults to true; when false, a request may select only one distinct resource. Every effective scope must appear in the scopes list of every selected resource. A scope that is valid for only one resource cannot be put into a token intended for several resources.
Enable required only after every affected client sends resource on authorization, code exchange, and refresh. Turning it on intentionally makes existing resource-less authorization families fail their next token request with invalid_target; it does not infer a resource from client configuration or a legacy audience.
Registered clients must also opt in to each resource under settings.openid.allowed_resources, which accepts at most 100 exact URIs:
{
"settings": {
"openid": {
"allowed_resources": [
"https://api.example.com/reports",
"https://api.example.com/exports"
]
}
}
}
The effective set for a registered client is the intersection of the issuer catalog and allowed_resources. An omitted or empty allowed_resources authorizes no RFC 8707 resource; it does not inherit the issuer catalog and does not implicitly authorize the client ID. A Client ID Metadata Document has no registered-client settings, so CIMD clients use the issuer catalog as their resource allowlist; the document’s own scope restrictions still apply.
Prior consent skips the consent screen only when the requested scopes and resources are both subsets of the same stored grant. Newly requested resources appear as read-only exact URIs on the consent screen; the browser can choose scopes but cannot add or replace resource values. A new consent decision replaces the previous scope-and-resource grant as one unit rather than unioning the two lists independently.
Errors
In authorization-code and refresh-token flows, malformed, missing-but-required, unknown, disallowed, excessive, or scope-incompatible resource selections fail with invalid_target. At the authorization endpoint, AuthPI redirects this error only after it has established that the supplied redirect_uri belongs to the client; the redirect includes error=invalid_target and the original state. If the client or redirect URI cannot be trusted—including an unresolved or invalid CIMD redirect—AuthPI returns a direct 400 JSON response and never redirects to the supplied URI.
At the token endpoint, invalid_target is always a direct 400 JSON response. Error descriptions do not enumerate the issuer’s resource catalog or the client’s allowlist.
Resource-rejection diagnostics classify failures as missing_required, malformed, too_many, multiple_disallowed, ambiguous_legacy, not_allowed, not_in_grant, scope_mismatch, policy_changed, or unknown. Diagnostic context is limited to the grant type, client kind, and resource count; requested resource URIs and configured allowlists are excluded.
The legacy audience parameter remains available for existing integrations and continues to use the registered client’s allowed_audiences. A request must not combine audience and resource; AuthPI rejects that ambiguity with invalid_request.
To migrate from audience:
- Add each protected-resource URI and its valid scopes to the issuer’s
resource_indicators.resources. - Add the same exact URI to each registered client’s
allowed_resources. - Send
resourceat both authorization and code exchange, then on refresh when selecting a subset. - Update resource-server verification to accept
audas either a string or an array containing its identifier. - Stop sending
audience; never send both parameters during a staged rollout.
Enable required resource selection
Start with required: false. Configure the issuer resource catalog and each registered client’s allowed_resources, then update every affected client to send exact configured resource values during authorization and permitted subsets during code exchange or refresh. Verify those requests before changing the issuer policy to required: true.
After required is enabled, existing authorization families that were created without a resource fail their next code-exchange or refresh request with invalid_target. Start a new authorization flow for those sessions. During a staged migration, send either audience or resource, never both.
MCP resource profile
The MCP authorization specification requires the MCP server’s canonical resource URI at authorization and token exchange. For an MCP server at https://mcp.authpi.com/mcp, configure one required resource and disable multiple-resource requests:
{
"settings": {
"security": {
"openid_policy": {
"resource_indicators": {
"required": true,
"allow_multiple": false,
"resources": [
{
"resource": "https://mcp.authpi.com/mcp",
"scopes": ["openid", "offline_access", "issuers:read"]
}
]
}
}
}
}
}
Registered clients must also include the exact string https://mcp.authpi.com/mcp in settings.openid.allowed_resources; CIMD clients are governed by the issuer entry. Variants such as https://mcp.authpi.com, https://mcp.authpi.com/mcp/, or a differently cased hostname do not match. Clients must send the exact configured value at authorization, code exchange, and refresh.
Selected Organizations
AuthPI supports an optional org parameter on the authorization request to issue tokens restricted to one organization:
GET /authorize?
...&
org=org_0gw3hcq8r2kfn7xj9tzm4be5a
The selected organization is stored with the authorization code and resulting session. /token does not accept org; token exchange and refresh use the trusted value from the authorization flow.
Validation happens before tokens are issued:
- If the client has
settings.restrictions.organizations.policy: "none", selected-org requests fail withinvalid_request. - If the client has
policy: "allowlist", the requested org must appear inallowed_org_ids. - If the user is not an active member of the selected org, the authorization-code exchange fails with
invalid_grant.
OpenID Connect Core 1.0
AuthPI is a fully compliant OpenID Connect Provider (OP).
ID Token
ID tokens are JWTs containing identity claims about the authenticated user.
Required claims:
| Claim | Description |
|---|---|
iss | Issuer identifier URL |
sub | Subject identifier (user ID) |
aud | Audience (client ID) |
exp | Expiration time |
iat | Issued at time |
Authentication claims:
| Claim | Description |
|---|---|
auth_time | Time of authentication |
nonce | Client-provided nonce (if sent in request) |
acr | Authentication context class reference |
amr | Authentication methods used |
at_hash | Access token hash |
Profile claims (when requested via scopes):
| Scope | Claims |
|---|---|
profile | name, given_name, family_name, picture, locale |
email | email, email_verified |
phone | phone_number, phone_number_verified |
address | address |
UserInfo Endpoint
Endpoint: GET|POST /{issuer_id}/userinfo
Returns claims about the authenticated user. Requires a valid access token with the openid scope.
GET /userinfo
Authorization: Bearer eyJ...
Response:
{
"sub": "usr_xxx",
"name": "Jane Doe",
"email": "jane@example.com",
"email_verified": true,
"picture": "https://example.com/photo.jpg"
}
Scopes
| Scope | Description |
|---|---|
openid | Required for OIDC flows; triggers ID token issuance |
profile | Basic profile information |
email | Email address and verification status |
phone | Phone number and verification status |
address | Physical address |
Nonce
The nonce parameter prevents replay attacks. When included in the authorization request, it’s embedded in the ID token for client verification.
GET /authorize?
...&
nonce=n-0S6_WzA2Mj
The client must verify that the nonce claim in the ID token matches the value sent in the request.
Authentication Context
ACR (Authentication Context Class Reference):
AuthPI returns ACR values indicating the authentication assurance level:
urn:authpi:assurance:loa1- Standard authenticationurn:authpi:method:{method}- Method-specific (e.g.,urn:authpi:method:passkey)
AMR (Authentication Methods References):
The amr claim contains an array of authentication methods used:
pwd- Passwordotp- One-time passwordmfa- Multi-factor authenticationhwk- Hardware key (passkey)
OpenID Connect Discovery 1.0
AuthPI publishes its configuration at the standard discovery endpoint.
Endpoint: GET /{issuer_id}/.well-known/openid-configuration
Response
{
"issuer": "https://idp.authpi.com/i_xxx",
"authorization_endpoint": "https://idp.authpi.com/i_xxx/authorize",
"token_endpoint": "https://idp.authpi.com/i_xxx/token",
"userinfo_endpoint": "https://idp.authpi.com/i_xxx/userinfo",
"jwks_uri": "https://idp.authpi.com/i_xxx/jwks.json",
"introspection_endpoint": "https://idp.authpi.com/i_xxx/introspect",
"revocation_endpoint": "https://idp.authpi.com/i_xxx/revoke",
"end_session_endpoint": "https://idp.authpi.com/i_xxx/logout",
"scopes_supported": ["openid", "email", "profile", "address", "phone"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["ES256", "RS256", "EdDSA"],
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
"code_challenge_methods_supported": ["S256"],
"claims_supported": [
"sub", "iss", "aud", "exp", "iat",
"name", "given_name", "family_name",
"email", "email_verified",
"picture", "locale",
"acr", "amr", "auth_time"
],
"frontchannel_logout_supported": false,
"frontchannel_logout_session_supported": false,
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true
}
When CIMD is enabled for the issuer, discovery also includes "client_id_metadata_document_supported": true. The property is omitted while CIMD is disabled.
JWKS Endpoint
Endpoint: GET /{issuer_id}/jwks.json
Returns the JSON Web Key Set containing public keys for verifying tokens.
{
"keys": [
{
"kty": "EC",
"use": "sig",
"kid": "key_xxx",
"alg": "ES256",
"crv": "P-256",
"x": "...",
"y": "..."
}
]
}
Keys are cached for 1 hour. Clients should cache JWKS responses and refresh periodically.
Session Management
AuthPI supports OIDC Session Management for detecting session changes.
Check Session Iframe
Endpoint: GET /{issuer_id}/check-session.html
Clients can embed this iframe and use postMessage to check if the user’s session is still valid without making network requests.
RP-Initiated Logout
Endpoint: GET /{issuer_id}/logout
GET /logout?
id_token_hint=eyJ...&
post_logout_redirect_uri=https://app.example.com/logged-out&
state=xyz
| Parameter | Required | Description |
|---|---|---|
id_token_hint | Recommended | ID token for session identification |
post_logout_redirect_uri | Optional | Where to redirect after logout |
state | Optional | CSRF protection, echoed back |
The post_logout_redirect_uri must be registered in the client’s configuration.
When AuthPI can identify the underlying OP session, RP-initiated logout terminates that SSO anchor and the linked RP/client sessions created from it. Each affected client session can receive a back-channel logout notification when the client is configured for it.
Front-Channel Logout
AuthPI does not currently advertise or send OIDC front-channel logout iframe notifications. Use back-channel logout for client session notifications.
Back-Channel Logout
AuthPI can send logout tokens directly to relying parties’ back-channel logout endpoints. This is the supported logout notification mechanism and does not depend on the user’s browser.
Client Authentication
Supported Methods
| Method | Description |
|---|---|
client_secret_basic | Client ID and secret in HTTP Basic header |
client_secret_post | Client ID and secret in POST body |
none | No authentication (public clients only) |
Basic Authentication:
POST /token
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=xxx&
redirect_uri=https://app.example.com/callback
POST Body Authentication:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=xxx&
redirect_uri=https://app.example.com/callback&
client_id=c_xxx&
client_secret=sec_xxx
Not Supported
private_key_jwt- JWT client assertion with private keyclient_secret_jwt- JWT client assertion with shared secrettls_client_auth- Mutual TLS authentication
Token Lifetimes
Default token lifetimes (configurable per client):
| Token Type | Default Lifetime |
|---|---|
| Authorization code | 10 minutes |
| Access token | 30 minutes |
| Refresh token | 7 days |
| ID token | Same as access token |
Error Responses
AuthPI returns OAuth 2.0 standard error responses:
{
"error": "invalid_grant",
"error_description": "The authorization code has expired"
}
Common error codes:
| Error | Description |
|---|---|
invalid_request | Missing or invalid parameter |
invalid_client | Client authentication failed |
invalid_grant | Authorization code or refresh token invalid |
unauthorized_client | Client not authorized for this grant type |
unsupported_grant_type | Grant type not supported |
invalid_scope | Requested scope is invalid or exceeds granted |
access_denied | User denied the authorization request |
Limitations
Features Not Implemented
- Hybrid flows:
response_typecombinations likecode id_tokenare not supported - Request objects: The
requestandrequest_uriparameters are not supported - Pushed Authorization Requests (RFC 9126): Not implemented
- DPoP (RFC 9449): Demonstration of Proof of Possession not supported
- CIBA: Client-Initiated Backchannel Authentication not supported
Parameter Limitations
promptparameter is recognized but not fully enforcedmax_ageparameter is not validatedui_localesparameter is not processedlogin_hintparameter is not used
Security Recommendations
For Confidential Clients
- Store client secrets securely (environment variables, secret managers)
- Use HTTPS for all redirect URIs
- Implement PKCE even though it’s optional
- Rotate client secrets periodically
For Public Clients
- PKCE is mandatory—always use
S256 - Store tokens securely (avoid localStorage for sensitive data)
- Use short-lived access tokens
- Implement token refresh handling
For All Clients
- Validate ID token signatures using JWKS
- Verify
noncein ID tokens matches your request - Check
audclaim matches your client ID - Implement proper CSRF protection with
stateparameter - Use token introspection for high-security operations
Next Steps
- Getting Started with AuthPI
- Clients configuration guide
- Sessions and token management
- Webhooks for authentication events