Skip to main content

Error reference

An OAuth error body has error and error_description. The first table lists every error value the server defines, generated from the code. The tables after it list messages by endpoint, with their causes. We triggered each one on a test environment unless the section says we read it in the code.

Error codes​

This table is generated from the OAuthError constants class and the status mapping in TokenExceptionHandler. A call site can override the default status, and the "Status set at a call site" column lists each override.

Error codeDefined byDefault HTTP statusStatus set at a call siteConstant referenced by
invalid_requestRFC 6749 Section 5.2400noneAuthorizationCodeGrantHandler, AuthorizeService, BackchannelAuthorizeController, CallerAuthenticator, CibaInitiationService, ClientAssertionValidator, ClientCredentialsGrantHandler, GrantValidation, OAuth2CallbackService, RefreshTokenGrantHandler, TokenController, TokenExchangeGrantHandler, TokenService
invalid_clientRFC 6749 Section 5.2401noneAuthorizeService, BackchannelAuthorizeController, CallerAuthenticator, ClientAssertionValidator, ClientIdMetadataService, GrantValidation, SpiffeAuthenticator, TokenExceptionHandler, TokenService
invalid_grantRFC 6749 Section 5.2400noneAuthorizationCodeGrantHandler, BackchannelAuthService, RefreshTokenGrantHandler, TokenExchangeGrantHandler, TokenService
unauthorized_clientRFC 6749 Section 5.2400noneBackchannelAuthorizeController, GrantValidation
unsupported_grant_typeRFC 6749 Section 5.2400noneTokenController
invalid_scopeRFC 6749 Section 5.2400noneRefreshTokenGrantHandler
access_deniedRFC 6749 Section 5.2400403 in CibaInitiationServiceAuthorizeService, CibaInitiationService, ObligationOrchestrator, TokenService
server_errorRFC 6749 Section 5.2400500 in CibaInitiationServiceAuthorizeService, CibaInitiationService, ClientIdMetadataService, OAuth2CallbackService, ObligationOrchestrator
invalid_tokenRFC 6750 Section 3.1401noneCallerAuthenticator, TokenExceptionHandler
insufficient_scopeRFC 6750 Section 3.1401noneCallerAuthenticator, TokenExceptionHandler
invalid_authorization_detailsRFC 9396 (RAR)400noneAuthorizeService, TokenController, TokenExceptionHandler
invalid_targetRFC 8693 (Token Exchange)400noneAuthorizationCodeGrantHandler, ClientCredentialsGrantHandler, RefreshTokenGrantHandler, TokenExchangeGrantHandler, TokenService
use_dpop_nonceRFC 9449 (DPoP)400noneTokenController
invalid_dpop_proofRFC 9449 (DPoP)400noneno class references the constant
approval_requiredOpenID CIBA Core 1.0400noneTokenExceptionHandler
authorization_pendingOpenID CIBA Core 1.0400noneTokenService
slow_downOpenID CIBA Core 1.0400noneTokenService
expired_tokenOpenID CIBA Core 1.0400noneTokenService
invalid_binding_messageOpenID CIBA Core 1.0400noneCibaInitiationService
temporarily_unavailableOpenID CIBA Core 1.0400503 in CibaInitiationServiceCibaInitiationService

invalid_dpop_proof is defined but never sent. An invalid DPoP proof leads to access_denied when the client must use DPoP, and to a Bearer token when it need not. See DPoP.

/token​

ResponseCause
400 invalid_request, scope is requiredNo scope and no authorization_details
400 invalid_request, resource must not include a fragmentresource has a #
400 invalid_target, Resource could not be resolved to a known typeresource maps to no registered type
400 unsupported_grant_type, Grant type not supported: implicitAny grant other than authorization_code, client_credentials, refresh_token, token exchange and CIBA, such as password or implicit
401 invalid_client, client_secret does not match the registered secretWrong secret
401 invalid_client, client_secret required — client is registered as confidentialA confidential client sent only its client_id
400 access_denied, Access deniedPolicy refused. The /token audit row carries the reason, such as grant_type_not_allowed, dpop_proof_required, client_denied or spiffe_no_path_grants.
400 access_denied, Access deniedA token exchange asked for more than the subject token was granted. The audit reason is token_exchange_actions_exceeded
invalid_grant, Subject token issuer is not trustedAn ID token exchange whose issuer is not in trusted_issuers. Read in the code.
400 invalid_grant, Invalid or expired actor tokenA token exchange sent an actor token the server did not issue
400 invalid_request, Unsupported subject_token_type: ...A token exchange subject type other than access_token or id_token
401 invalid_client, JWT-SVID aud claim does not contain expected audience: ...A SPIFFE SVID minted for another audience
400 approval_requiredPolicy wants a person to approve. We read this in the code. See CIBA approval.

The authorization code grant can also return invalid_grant for an unknown, expired, used or mismatched code, or a wrong code_verifier. We read these in the code.

CIBA polling at /token​

Every answer below is HTTP 400. We read them in the code. The integration test test_ciba.py checks each one.

errorCause
authorization_pendingNo decision yet
slow_downPolled inside the interval
access_deniedThe approver refused
expired_tokenNo decision within expires_in
invalid_grantUnknown auth_req_id, another client's, or already used. We saw Unknown auth_req_id.

/bc-authorize​

ResponseCause
400 invalid_request, Policy does not require approval for this request; request the token directlyPolicy grants the request without approval
400 invalid_request, Exactly one of login_hint, id_token_hint or login_hint_token is requiredNo hint was sent
400 invalid_requestA hint that is not login_hint or does not name the approver, no binding_message, or more than one distinct approval needed
400 invalid_binding_messageThe message differs from the one policy shows the approver
400 unauthorized_clientA public client
401 invalid_clientMissing or wrong credentials
403 access_denied, Policy denies this requestPolicy refuses outright
503 temporarily_unavailableThe approval IdP did not accept the notification
500 server_errorApproval is misconfigured on the server

We triggered the first two rows and the invalid_client row. We read the others in the code.

/authorize​

These come back as a JSON body, not a redirect.

ResponseCause
400 invalid_request, response_type must be 'code'Any other response_type, such as token
400 invalid_request, PKCE code_challenge_method 'plain' is not allowed; use S256A plain challenge
400 invalid_request, redirect_uri not registered for clientA redirect URI the client did not register. Read in the code.
401 invalid_client, Unknown clientAn unknown client_id that is not a metadata document URL. Read in the code.

Some errors go to the redirect URI instead, as error and error_description query parameters. A public client with no code_challenge gets error=invalid_request, which we read in the code. A request with no session and no identity provider to send the user to got error=login_required.

/register​

Every refusal is HTTP 400.

error and descriptionCause
invalid_redirect_uriA redirect URI that is not https, loopback http or a private-use scheme
invalid_client_metadata, Registration denied: no_overlapping_grant_typesNo requested grant type is allowed for registration without a statement
invalid_client_metadata, Registration denied: auth_method_not_allowedThe auth method is not in allowed_auth_methods
invalid_client_metadata, Registration denied: missing_software_statementA statement is required and none was sent
invalid_client_metadata, Registration denied: missing_explicit_declarations:grant_typesThe statement has no grant_types
invalid_software_statement, The software statement could not be parsed or verified.Unsigned, tampered or unverifiable
invalid_software_statement, Registration denied: untrusted_issuerThe issuer is not in trusted_issuers
unapproved_software_statement, Registration denied: denylist:software_id:<id>The software ID is denylisted. An issuer gives denylist:issuer:<issuer>.
unapproved_software_statement, Registration denied: invalid_resource_typeThe statement names a type missing from the registry
registration_requires_approvalThe statement has "trust_level": "low"

A request with no redirect_uris gets a generic HTTP 400 Bad Request body instead of an OAuth error.

/introspect​

ResponseCause
200 {"active": false, "inactive_reason": "invalid_token"}The token is unknown, expired or revoked
200 {"active": false, "inactive_reason": "insufficient_scope"}Policy refused the call described by context
401 invalid_client, client_id or Bearer token is requiredNo caller credentials
401 invalid_client, Client authentication failedUnknown client or wrong secret
401 invalid_client, Client is not entitled to introspection or uma_protection scopeThe caller lacks the scope

/revoke​

/revoke answers HTTP 200 with an empty body for a known or an unknown token. A wrong client secret is the exception, with HTTP 401 invalid_client. A 200 does not mean the token was revoked. A token issued to another confidential client stays active, and a request with no client credentials revokes only a token issued to a public client. See Revocation.

Admin API​

ResponseCause
401 {"error": "unauthorized", "error_description": "Valid admin API key required"}Missing or wrong X-Admin-API-Key
409 {"error": "Client with client_id '<id>' already exists"}Creating a client that already exists
422 {"error": "Policy data failed schema validation", "failures": [...]}A control row that breaks its schema