API Error Reference
API Version: 5.24.0
OAuth 2.0 Error Codes
Standard OAuth 2.0 errors from RFC 6749. Returned from authorization and token endpoints.
Authorization Endpoint Errors
Returned as query parameters in redirect URL:
https://yourapp.com/callback?error=ERROR_CODE&error_description=Message
access_denied
- Cause: User denied authorization or lacks app permission
- HTTP: 302 redirect with error in query params
- Action: Check permission status (pending/revoked/none), show appropriate message
invalid_client
- Cause: Unknown client_id or client suspended
- Action: Verify client_id, contact SSO admins
invalid_scope
- Cause: Requested scope not in client's allowed_scopes
- Action: Only request registered scopes
unauthorized_client
- Cause: Grant type not allowed for this client
- Action: Verify OAuth client configuration
invalid_request
- Cause: Missing required parameter or malformed request
- Action: Check client_id, redirect_uri, response_type, scope
Token Endpoint Errors
Returned as JSON response body:
{
"error": "ERROR_CODE",
"error_description": "Human-readable message"
}invalid_grant
HTTP 400 Bad Request
- Cause: Authorization code expired (10 min), already used, or invalid
- Action: Restart OAuth flow from /api/oauth/authorize
{
"error": "invalid_grant",
"error_description": "Authorization code expired or already used"
}invalid_client
HTTP 401 Unauthorized
- Cause: Wrong client_secret or invalid client_id
- Action: Verify environment variables
redirect_uri_mismatch
HTTP 400 Bad Request
- Cause: redirect_uri in token request differs from authorization request
- Action: Use exact same redirect_uri in both requests
unsupported_grant_type
HTTP 400 Bad Request
- Cause: Invalid grant_type value
- Action: Use "authorization_code" or "refresh_token"
App Permission Error Codes
Errors specific to SSO app-level permission system:
APP_PERMISSION_DENIED
HTTP 403 Forbidden
User does not have permission to access this application.
{
"error": {
"code": "APP_PERMISSION_DENIED",
"message": "User does not have permission to access this application",
"status": "pending" // or "revoked" or "none"
}
}Status-specific messages:
pending- "Your access request is pending admin approval."revoked- "Your access has been revoked. Contact support."none- "You don't have access. Contact administrator."
APP_PERMISSION_INSUFFICIENT_ROLE
HTTP 403 Forbidden
User has access but insufficient role for operation.
{
"error": {
"code": "APP_PERMISSION_INSUFFICIENT_ROLE",
"message": "Admin role required",
"currentRole": "user",
"requiredRole": "admin"
}
}Authentication Error Codes
INVALID_TOKEN
HTTP 401 Unauthorized
- Cause: Token malformed, invalid signature, or tampered
- Action: Try refresh token, then re-authenticate
TOKEN_EXPIRED
HTTP 401 Unauthorized
{
"error": {
"code": "TOKEN_EXPIRED",
"message": "Access token has expired",
"expiredAt": "2025-10-15T17:22:16.000Z"
}
}- Cause: Access token older than 1 hour
- Action: Use refresh token to get new access token
INVALID_CREDENTIALS
HTTP 401 Unauthorized
- Cause: Wrong email or password (direct login)
- Action: Check credentials, note: rate limited after 10 failures
UNAUTHORIZED
HTTP 401 Unauthorized
- Cause: No authentication provided
- Action: Include Authorization: Bearer header
Validation Error Codes
INVALID_INPUT
HTTP 400 Bad Request
{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"details": [
{
"field": "email",
"message": "Invalid email format"
},
{
"field": "password",
"message": "Password must be at least 8 characters"
}
]
}
}EMAIL_EXISTS
HTTP 400 Bad Request
- Cause: Email already registered
- Action: User should login instead
MISSING_REQUIRED_FIELD
HTTP 400 Bad Request
- Cause: Required field missing from request body
- Action: Check API endpoint documentation for required fields
Rate Limiting Errors
rate_limit_exceeded
HTTP 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": "rate_limit_exceeded",
"error_description": "Too many requests. Retry after 60 seconds.",
"retry_after": 60
}- Action: Wait retry_after seconds, implement exponential backoff
Admin API Error Codes
ADMIN_AUTH_REQUIRED
HTTP 401 Unauthorized
- Cause: Missing or invalid admin session cookie
- Action: Redirect to /admin login
INSUFFICIENT_ADMIN_PERMISSIONS
HTTP 403 Forbidden
- Cause: Operation requires super-admin, user is only admin
- Action: Contact super-admin for this operation
USER_NOT_FOUND
HTTP 404 Not Found
- Cause: User UUID doesn't exist
- Action: Verify user ID is correct
Server Error Codes
INTERNAL_ERROR
HTTP 500 Internal Server Error
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"requestId": "req_abc123",
"timestamp": "2025-10-15T16:22:16.000Z"
}
}- Action: Retry with exponential backoff, contact support with requestId if persists
DATABASE_ERROR
HTTP 500 Internal Server Error
- Cause: Database connection or query failed
- Action: Usually transient, retry after delay
Error Handling Best Practices
1. Check Error Code, Not Message
Always use error.code for logic (messages may change):
// ✅ CORRECT
if (error.code === 'APP_PERMISSION_DENIED') {
if (error.status === 'pending') {
showPendingMessage();
}
}
// ❌ WRONG
if (error.message.includes('permission')) {
// Message text may change!
}2. Implement Retry Logic
For transient errors (429, 500s), use exponential backoff:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
continue;
}
if (response.status >= 500) {
await sleep(Math.pow(2, i) * 1000);
continue;
}
return response;
} catch (err) {
if (i === maxRetries - 1) throw err;
await sleep(Math.pow(2, i) * 1000);
}
}
}3. Show User-Friendly Messages
Map error codes to user-friendly text:
const ERROR_MESSAGES = {
'APP_PERMISSION_DENIED': {
pending: 'Your access is pending approval.',
revoked: 'Your access was revoked.',
none: "You don't have access."
},
'TOKEN_EXPIRED': 'Session expired. Please login.',
'RATE_LIMIT_EXCEEDED': 'Too many requests. Wait and retry.',
'INTERNAL_ERROR': 'Something went wrong.'
};
function getUserMessage(error) {
if (error.code === 'APP_PERMISSION_DENIED') {
return ERROR_MESSAGES[error.code][error.status];
}
return ERROR_MESSAGES[error.code] || 'An error occurred.';
}4. Handle OAuth Errors Specially
OAuth errors come in query params OR JSON:
// Authorization callback
const params = new URLSearchParams(window.location.search);
if (params.has('error')) {
const error = params.get('error');
if (error === 'access_denied') {
showAccessDenied();
}
}
// Token endpoint
const response = await fetch('/api/oauth/token', {...});
const data = await response.json();
if (!response.ok && data.error === 'invalid_grant') {
window.location.href = '/login'; // Restart OAuth
}5. Log Errors (But Not Secrets!)
try {
const response = await fetch(url, options);
const data = await response.json();
if (!response.ok) {
console.error('API Error:', {
url,
status: response.status,
error: data.error,
requestId: data.error?.requestId,
timestamp: new Date().toISOString()
// NEVER log: passwords, tokens, secrets
});
}
} catch (err) {
console.error('Network Error:', err);
}Related Documentation
- Complete Endpoint Reference - All API endpoints with examples
- Response Formats - Token structures and response schemas
- Authentication Guide - OAuth 2.0 flow details
- App Permissions - Permission system documentation
- Admin Approval - How SSO admins manage access