Skip to Content
MuoCeon Docs
Third-party OAuth IntegrationReference

Error codes

Two error response formats, every error code, and a troubleshooting order.

MuoCeon's OAuth interfaces use two error formats depending on where the failure happens. Your client must parse both — do not treat the unified envelope as a site-wide convention.

Format 1: protocol endpoints (RFC 6749 §5.2)

Applies to token, revoke, introspect. These endpoints must speak the standard language, or standard libraries cannot interpret them:

{
  "error": "invalid_grant",
  "error_description": "The authorization code has already been used"
}
errorHTTPMeaningWhere to look
invalid_request400Missing or duplicated parameters, unsupported grant_typeCheck form fields and Content-Type
invalid_client401Client authentication failedWrong secret, wrong Basic encoding, public client wrongly sending a secret
invalid_grant400Code/refresh token invalid, used or expired; PKCE or redirect_uri mismatchA code exchanges once only; redirect_uri must match verbatim
unauthorized_client400The client may not use this grant typeE.g. a third party using client_credentials
invalid_scope400Invalid scope, or attempting to widen on refreshOnly registered delegable scopes
server_error500Server-side failureReport with the request time and client_id

Format 2: unified envelope

Applies to preauthorize, authorize, grants and other internal or management endpoints, plus rate-limit responses everywhere:

{
  "success": false,
  "code": "OAUTH_INVALID_REDIRECT_URI",
  "message": "Redirect URI is not registered for this client: https://...",
  "details": ["redirect_uri must match a registered value"],
  "timestamp": "2026-01-01T00:00:00.000Z"
}
codeHTTPMeaning
OAUTH_CLIENT_NOT_FOUND400client_id is not registered
OAUTH_INVALID_REDIRECT_URI400Redirect URI unregistered or shape-invalid
OAUTH_INVALID_REQUEST400Authorization request parameters are malformed
OAUTH_INVALID_CONSENT_TICKET400Consent ticket missing, expired, consumed, or bound to a different client/account/session
OAUTH_INVALID_AUTHORIZATION_DETAILS400authorization_details type/action not on the allowlist
OAUTH_INVALID_ASSERTION401Identity assertion invalid or expired
OAUTH_ASSERTION_REPLAY400Identity assertion already used
INSUFFICIENT_USER_AUTHENTICATION401Authentication strength insufficient; step-up needed (ticket is not consumed)
OAUTH_TOO_MANY_REQUESTS429Rate limited; response carries Retry-After
UNAUTHENTICATED401Resource endpoints: access token invalid or expired
FORBIDDEN403Resource endpoints: audience or scope requirements not met

Ticket errors are deliberately not split

OAUTH_INVALID_CONSENT_TICKET merges "does not exist", "already consumed" and "binding mismatch" into one error: splitting them would tell an attacker "the ticket is genuine, only the client is wrong". For legitimate clients all three mean the same thing — start the authorization flow again.

Format 3: redirect errors

When the user denies or the authorization request is rejected, the error appears on the redirect URI rather than in an API response:

https://your-app.example.com/callback?error=access_denied&state=k3Jd9x&iss=https%3A%2F%2Fid.example.com%2Fv1%2Foauth

Validate state and iss first, then handle error. access_denied means the user explicitly refused — do not retry automatically; that only makes them refuse again.

Rate limiting

  • Each endpoint counts independently; exceeding token does not affect jwks for the same IP.
  • Response: 429 + Retry-After (seconds).
  • Honour Retry-After; do not retry immediately. Use randomised backoff for batch refreshes.

Troubleshooting order

When something fails, locate it in this order; it covers the vast majority of cases:

  1. Parameters: does redirect_uri match the registered value verbatim (trailing slash, port)?
  2. Client: does the confidential client send its secret, does a public client wrongly send one, is client_id correct?
  3. Code / refresh token: already used (codes are single-use, refresh rotates)?
  4. PKCE: do code_verifier and code_challenge pair up, and is the method S256?
  5. Audience and scope: is UserInfo called with an auth audience token; were scopes filtered?
  6. Authentication strength: do acr_values / max_age demand too much?

On this page