Handling Authentication Errors

1. Understanding Authentication Error Codes

CodeMeaning
400Malformed request
401Missing/invalid credentials
403Authenticated but forbidden
429Rate limit exceeded
503Auth service unavailable

2. Implementing 401 Unauthorized Responses

Example: WWW-Authenticate

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api",
  error="invalid_token",
  error_description="The access token expired"
Content-Type: application/problem+json

{"type":"...","title":"Unauthorized","status":401}

3. Using 403 Forbidden Responses

UseDetail
AuthenticatedIdentity verified
Insufficient permissionCannot perform action
OptionalReturn 404 to hide resource existence

4. Implementing Error Messages

PracticeDetail
User-facingFriendly + actionable
Machine-readableStable error codes
No internalsStack traces in logs only

5. Preventing Information Disclosure

Anti-patternFix
"User not found""Invalid email or password"
"Wrong password""Invalid email or password"
Stack traceGeneric 500 to user
Version disclosureSuppress Server header

6. Using Generic Error Responses

Example: RFC 7807 problem+json

{
  "type": "https://app.example/problems/auth-failed",
  "title": "Authentication failed",
  "status": 401,
  "code": "auth.invalid_credentials",
  "trace_id": "01HK..."
}

7. Implementing Token Expiration Handling

ServerClient
401 + error="invalid_token", error_description="expired"Trigger silent refresh; retry once

8. Using Standardized Error Format

StandardDetail
RFC 7807problem+json
RFC 6750OAuth Bearer error params
RFC 9457Updated problem details (2023)

9. Implementing WWW-Authenticate Header

ParamDetail
realmProtection space
errorinvalid_request | invalid_token | insufficient_scope
error_descriptionHuman-readable
scopeRequired scopes (for insufficient_scope)

10. Handling Errors in Client Applications

Example: Axios interceptor

axios.interceptors.response.use(r => r, async (err) => {
  if (err.response?.status === 401 && !err.config._retry) {
    err.config._retry = true;
    await refreshToken();
    return axios(err.config);
  }
  throw err;
});