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
scopeformat - Missing
codein 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:
- Verify your client ID and secret are correct
- Check if your client is approved in the Developer Portal
- 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_uriin 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_credentialswhen 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-tokenheader - 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
| Status | Meaning | Common Causes |
|---|---|---|
400 | Bad Request | Invalid parameters, validation errors |
401 | Unauthorized | Invalid/expired token, authentication required |
403 | Forbidden | Insufficient permissions, client not approved |
404 | Not Found | Resource doesn't exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side error |
503 | Service Unavailable | Maintenance 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_supportedgrant_types_supportedscopes_supportedcode_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
| Error | Likely Cause | Fix |
|---|---|---|
redirect_uri_mismatch | Redirect URI doesn't match registered | Update in Developer Portal |
invalid_state | State parameter mismatch | Verify state in session matches |
code_verifier_invalid | PKCE verifier doesn't match | Store verifier in session correctly |
token_expired | Access token expired | Use refresh token or re-authenticate |
insufficient_scope | Token doesn't have required scope | Request additional scopes |
Getting Help
If you encounter errors not covered here:
- Check the API Reference for endpoint-specific details
- Enable debug logging and review the console
- Contact support with the error details and request ID (if provided)
Next Steps
- Review the Authentication Flow
- Understand Scopes and Claims
- Explore the API Reference