Skip to main content

Error Codes

ConsentKeys uses standard OAuth 2.0 error codes plus some custom ones for specific scenarios. This reference helps you handle and debug authentication errors.

Error Response Format

OAuth/OIDC Endpoints

Protocol endpoints (/auth, /token, /introspect, etc.) use OAuth 2.0 format:

{
"error": "invalid_request",
"error_description": "The redirect_uri parameter is missing"
}

REST API Endpoints

Regular API endpoints use a different format:

{
"error": "ValidationError",
"message": "Invalid client ID format"
}

Standard OAuth 2.0 Errors

invalid_request

Cause: Missing or malformed required parameters

Common scenarios:

  • Missing client_id
  • Missing redirect_uri
  • Invalid scope format
  • Missing code in token exchange

Example:

{
"error": "invalid_request",
"error_description": "The redirect_uri parameter is required"
}

Solution: Check your authorization URL or token request has all required parameters.


invalid_client

Cause: Invalid client credentials

Common scenarios:

  • Wrong client_id
  • Wrong client_secret
  • Client not approved yet
  • Client has been deleted

Example:

{
"error": "invalid_client",
"error_description": "Client authentication failed"
}

Solution:

  1. Verify your client ID and secret are correct
  2. Check if your client is approved in the Developer Portal
  3. Ensure you're not using a deleted client

invalid_grant

Cause: Authorization code is invalid or expired

Common scenarios:

  • Code already used (codes are single-use)
  • Code expired (10 minutes)
  • Code doesn't match the client
  • Wrong redirect_uri in token exchange

Example:

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

Solution: Restart the authorization flow to get a new code.


unauthorized_client

Cause: Client is not allowed to perform this action

Common scenarios:

  • Trying to use client_credentials when not configured
  • Client not approved for requested grant type
  • Redirect URI not registered

Example:

{
"error": "unauthorized_client",
"error_description": "This client is not authorized to use this grant type"
}

Solution: Verify your client configuration in the Developer Portal.


access_denied

Cause: User declined to authorize your application

Common scenarios:

  • User clicked "Deny" on consent screen
  • User closed the browser during auth

Example:

{
"error": "access_denied",
"error_description": "The user denied the authorization request"
}

Solution: This is a user choice. Display a friendly message explaining why your app needs access.

function AccessDenied() {
return (
<div>
<h2>Authorization Required</h2>
<p>
We need access to your email to create your account.
Without it, we cannot provide our service.
</p>
<button onClick={() => window.location.href = '/login'}>
Try Again
</button>
</div>
);
}

unsupported_response_type

Cause: Invalid response_type parameter

Example:

{
"error": "unsupported_response_type",
"error_description": "The response_type must be 'code'"
}

Solution: Use response_type=code for authorization code flow.


invalid_scope

Cause: Requested scope is not supported

Common scenarios:

  • Typo in scope name
  • Requesting a scope that doesn't exist
  • Invalid scope format (not space-separated)

Example:

{
"error": "invalid_scope",
"error_description": "The scope 'invalid_scope_name' is not supported"
}

Solution: Check the supported scopes and verify spelling.


server_error

Cause: Internal server error on ConsentKeys side

Example:

{
"error": "server_error",
"error_description": "An unexpected error occurred"
}

Solution: This is usually temporary. Retry after a brief delay. If it persists, contact support.


temporarily_unavailable

Cause: Service is temporarily down for maintenance

Example:

{
"error": "temporarily_unavailable",
"error_description": "The authorization server is currently undergoing maintenance"
}

Solution: Retry after a short delay (exponential backoff recommended).


ConsentKeys-Specific Errors

invalid_token

Cause: Magic link token is invalid or expired

Common scenarios:

  • Magic link expired (15 minutes)
  • Token already used
  • Token signature invalid

Example:

{
"error": "invalid_token",
"error_description": "The magic link has expired or is invalid"
}

Solution: Request a new magic link.


too_many_requests

Cause: Rate limit exceeded

Common scenarios:

  • Too many magic link requests (20/hour per email)
  • Too many API calls (100/minute general, 20/minute for session endpoints)

Example:

{
"error": "too_many_requests",
"error_description": "Too many requests. Please try again later."
}

Response headers:

RateLimit-Limit: 20
RateLimit-Remaining: 0
RateLimit-Reset: 3600

Solution: Wait for the rate limit to reset (check RateLimit-Reset header).


referral_required

Cause: A referral code is required to create an account (closed beta)

Example:

{
"error": "referral_required",
"error_description": "A referral code is required to create an account"
}

Solution: Provide a valid referral code in the magic link request.


invalid_referral_code

Cause: The provided referral code is invalid

Example:

{
"error": "invalid_referral_code",
"error_description": "The referral code is invalid or has been used too many times"
}

Solution: Verify the referral code or request a new one.


invalid_csrf_token

Cause: CSRF token validation failed

Common scenarios:

  • Missing x-csrf-token header
  • Token mismatch
  • Token expired

Example:

{
"error": "invalid_csrf_token",
"error_description": "CSRF token validation failed"
}

Solution: Obtain a new CSRF token from the session endpoint before making the request.


HTTP Status Codes

StatusMeaningCommon Causes
400Bad RequestInvalid parameters, validation errors
401UnauthorizedInvalid/expired token, authentication required
403ForbiddenInsufficient permissions, client not approved
404Not FoundResource doesn't exist
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error
503Service UnavailableMaintenance or overload

Error Handling Best Practices

1. Display User-Friendly Messages

Don't show raw error codes to users:

function getErrorMessage(error: string): string {
const messages = {
invalid_request: 'Something went wrong. Please try again.',
access_denied: 'You need to grant permission to use this app.',
invalid_grant: 'Your session expired. Please log in again.',
server_error: 'Our servers are having issues. Please try again later.',
too_many_requests: 'Too many attempts. Please wait a few minutes.',
};

return messages[error] || 'An unexpected error occurred.';
}

2. Log Errors for Debugging

function handleOAuthError(error: any) {
// Log technical details for developers
console.error('OAuth Error:', {
error: error.error,
description: error.error_description,
timestamp: new Date().toISOString(),
url: window.location.href,
});

// Show user-friendly message
showNotification(getErrorMessage(error.error));
}

3. Implement Retry Logic

async function tokenExchange(code: string, retries = 3): Promise<Tokens> {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch('/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: '...',
client_secret: '...',
}),
});

const data = await response.json();

if (response.ok) {
return data;
}

// Don't retry on client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new Error(data.error_description);
}

// Retry on server errors (5xx)
if (i < retries - 1) {
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
continue;
}

throw new Error(data.error_description);
} catch (error) {
if (i === retries - 1) throw error;
}
}
}

4. Handle Network Errors

try {
const response = await fetch('/token', { ... });
} catch (error) {
if (error instanceof TypeError) {
// Network error (offline, DNS failure, etc.)
showNotification('Network error. Check your connection.');
} else {
showNotification('An unexpected error occurred.');
}
}

Debugging Tips

Enable Detailed Logging

const DEBUG = process.env.NODE_ENV === 'development';

function logOAuthFlow(step: string, data: any) {
if (DEBUG) {
console.log(`[OAuth] ${step}:`, data);
}
}

// Use throughout your auth flow
logOAuthFlow('Authorization URL', authorizationUrl);
logOAuthFlow('Callback received', { code, state });
logOAuthFlow('Tokens received', { hasAccessToken: !!tokens.access_token });

Verify OAuth Parameters

Use the ConsentKeys OIDC Discovery endpoint:

curl https://pseudoidc.consentkeys.com/.well-known/openid-configuration

Verify your parameters match the supported values:

  • response_types_supported
  • grant_types_supported
  • scopes_supported
  • code_challenge_methods_supported

Test Error Scenarios

Intentionally trigger errors to test your handling:

// Test invalid client ID
const badClientId = 'ck_invalid';

// Test expired code (wait 10+ minutes)
const oldCode = 'code_from_10_minutes_ago';

// Test invalid redirect URI
const wrongRedirectUri = 'https://wrong-domain.com';

Rate Limit Handling

When you hit rate limits, respect the headers:

async function makeRequest(url: string) {
const response = await fetch(url);

if (response.status === 429) {
const resetTime = response.headers.get('RateLimit-Reset');
const waitSeconds = parseInt(resetTime || '60');

console.warn(`Rate limited. Retry in ${waitSeconds} seconds`);

// Wait and retry
await sleep(waitSeconds * 1000);
return makeRequest(url);
}

return response.json();
}

Common Errors and Solutions

ErrorLikely CauseFix
redirect_uri_mismatchRedirect URI doesn't match registeredUpdate in Developer Portal
invalid_stateState parameter mismatchVerify state in session matches
code_verifier_invalidPKCE verifier doesn't matchStore verifier in session correctly
token_expiredAccess token expiredUse refresh token or re-authenticate
insufficient_scopeToken doesn't have required scopeRequest additional scopes

Getting Help

If you encounter errors not covered here:

  1. Check the API Reference for endpoint-specific details
  2. Enable debug logging and review the console
  3. Contact support with the error details and request ID (if provided)

Next Steps