Skip to content

Error Reference

SingleSign returns errors in a consistent JSON format across all endpoints. This page documents every error code, what causes it, and how to fix it.


Error Response Format

All error responses follow this structure:

{
  "error": "error_code",
  "error_description": "A human-readable description of the error."
}
FieldTypeDescription
errorstringA machine-readable error code (see table below).
error_descriptionstringA human-readable explanation of the error. Not intended for end users — use it for debugging.

Authorization Endpoint Errors

Errors from the /oauth/authorize endpoint are returned as query parameters on the redirect URI:

https://app.example.com/callback?error=access_denied&error_description=The+user+denied+the+request&state=abc123

Token / Introspect / Revoke Endpoint Errors

Errors from POST endpoints are returned as JSON in the response body with an appropriate HTTP status code:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "invalid_grant",
  "error_description": "The authorization code has expired."
}

Error Codes

invalid_request

HTTP Status: 400

The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.

Common Causes:

  • Missing platform_guid parameter.
  • Missing redirect_uri in the token request.
  • Missing grant_type in the token request.
  • Malformed URL encoding.

Troubleshooting:

  1. Verify all required parameters are present. Check the Endpoint Reference for the complete parameter list.
  2. Ensure parameters are properly URL-encoded.
  3. Check that Content-Type is set to application/x-www-form-urlencoded for POST requests.
  4. Make sure no parameter is included more than once.
# Check: Is platform_guid present?
curl -X POST "https://api.singlesign.com/oauth/token" \
  -d "grant_type=authorization_code&code=xxx&redirect_uri=...&client_id=...&platform_guid=YOUR_GUID"
#                                              This is required ──────────────────────────────┘

invalid_client

HTTP Status: 401

Client authentication failed. The client_id is unknown, no client authentication was provided, or the authentication method is not supported.

Common Causes:

  • Wrong client_id.
  • Wrong client_secret for confidential clients.
  • Sending client_secret for a public client (not expected).
  • Malformed Basic auth header.

Troubleshooting:

  1. Double-check your client_id in the developer portal.
  2. For confidential clients, verify the client_secret is correct and hasn't been rotated.
  3. Ensure you're using the right authentication method: Basic auth header or POST body parameters.
  4. Check for extra whitespace or newlines in your credentials.
# Confidential client: verify credentials work
curl -X POST "https://api.singlesign.com/oauth/token" \
  -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
  -d "grant_type=authorization_code&code=xxx&redirect_uri=...&platform_guid=YOUR_GUID"

invalid_grant

HTTP Status: 400

The authorization code, refresh token, or PKCE verifier is invalid, expired, or has already been used.

Common Causes:

  • The authorization code has expired (codes are valid for 10 minutes).
  • The authorization code has already been exchanged (single-use).
  • The code_verifier does not match the code_challenge sent during authorization.
  • The redirect_uri in the token request does not match the one used in the authorization request.
  • The refresh token has been revoked or expired.

Troubleshooting:

  1. Expired code: Authorization codes expire after 10 minutes. If the user took too long, redirect them to authorize again.
  2. Code already used: Codes are single-use. If you're retrying a failed request, the code may have already been consumed. Start a new authorization flow.
  3. PKCE mismatch: Ensure the code_verifier sent to /oauth/token is the exact same value used to generate the code_challenge sent to /oauth/authorize. Do not regenerate it — retrieve it from storage.
  4. Redirect URI mismatch: The redirect_uri in the token request must be identical to the one in the authorization request.
# Common fix: Make sure code_verifier matches code_challenge
# code_challenge = BASE64URL(SHA256(code_verifier))
echo -n "YOUR_CODE_VERIFIER" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '='
# The output should match the code_challenge you sent to /authorize

unauthorized_client

HTTP Status: 400

The client is not authorized to use the requested grant type or scope.

Common Causes:

  • A public client attempting to use client_credentials grant.
  • Requesting a scope that is not configured for the application.
  • Using a grant type not enabled for the application.

Troubleshooting:

  1. Check your application's settings in the developer portal.
  2. Verify the requested scopes match those configured for your app.
  3. Ensure you're using the correct grant type for your client type (authorization_code for user authentication).

unsupported_grant_type

HTTP Status: 400

The authorization server does not support the requested grant type.

Common Causes:

  • Typo in the grant_type parameter.
  • Using implicit or client_credentials (not supported).
  • Missing the grant_type parameter entirely.

Troubleshooting:

  1. SingleSign supports two grant types: authorization_code and refresh_token.
  2. Check for typos: grant_type=authorization_code (not auth_code, code, etc.).
# Correct grant types:
grant_type=authorization_code    # For code exchange
grant_type=refresh_token         # For token refresh

invalid_scope

HTTP Status: 400

The requested scope is invalid, unknown, or exceeds the scopes granted to the client.

Common Causes:

  • Typo in a scope name.
  • Requesting a scope not registered for your app.
  • Missing the openid scope (required for OIDC).

Troubleshooting:

  1. Check spelling. Valid scopes are: openid, profile, email, phone, address, offline_access.
  2. Ensure the scopes are registered for your app in the developer portal.
  3. Always include openid as the first scope.
# Valid scope string:
scope=openid profile email

# Invalid examples:
scope=open_id profile email        ← typo (open_id vs openid)
scope=profile email                ← missing openid
scope=openid profile email admin   ← admin is not a valid scope

access_denied

HTTP Status: 403 (or redirect with error parameter)

The resource owner (user) denied the authorization request, or the server denied the request for another reason.

Common Causes:

  • The user clicked "Deny" on the consent screen.
  • The user's account is suspended or restricted.
  • Platform-level restrictions prevent the authorization.

Troubleshooting:

  1. If the user denied consent, show a friendly message and offer to try again.
  2. Do not automatically retry — the user made a deliberate choice.
  3. If this happens unexpectedly, check whether the user's account status is active.
const error = params.get("error");
if (error === "access_denied") {
  showMessage(
    "You declined the sign-in request. You can try again whenever you're ready."
  );
}

redirect_uri_mismatch

HTTP Status: 400 (returned directly, not via redirect)

The redirect_uri provided does not match any registered redirect URI for the application.

Common Causes:

  • Trailing slash mismatch (/callback vs /callback/).
  • Port mismatch (localhost:3000 vs localhost:5173).
  • Scheme mismatch (http vs https).
  • Path mismatch (/callback vs /auth/callback).
  • The URI was never registered in the developer portal.

Troubleshooting:

  1. Copy the exact redirect_uri from your authorization request.
  2. Compare it character-by-character with the URIs in your developer portal.
  3. See Redirect URIs for detailed matching rules.

server_error

HTTP Status: 500

An unexpected error occurred on SingleSign's servers.

Troubleshooting:

  1. Retry the request after a short delay (use exponential backoff).
  2. If the error persists, check the SingleSign status page for outages.
  3. Contact support if the issue continues.

temporarily_unavailable

HTTP Status: 503

The authorization server is temporarily unable to handle the request due to maintenance or overload.

Troubleshooting:

  1. Retry with exponential backoff.
  2. Check the Retry-After response header for the recommended wait time.
  3. See Rate Limits for best practices.

HTTP Status Code Summary

StatusMeaningCommon Error Codes
400Bad Requestinvalid_request, invalid_grant, invalid_scope, unauthorized_client, unsupported_grant_type
401Unauthorizedinvalid_client
403Forbiddenaccess_denied
429Too Many Requests(rate limited — see Rate Limits)
500Internal Server Errorserver_error
503Service Unavailabletemporarily_unavailable

Best Practices for Error Handling

  1. Always check error before processing a response. Both redirect callbacks and JSON responses may contain errors.
  2. Log error and error_description for debugging, but show user-friendly messages to end users.
  3. Don't expose error_description to users — it may contain internal details.
  4. Implement retry logic for server_error and temporarily_unavailable with exponential backoff.
  5. Handle invalid_grant gracefully — redirect the user to log in again rather than showing a cryptic error.

Next Steps

Last updated: 2026-02-16