> For the complete documentation index, see [llms.txt](https://oten.gitbook.io/identity-support/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://oten.gitbook.io/identity-support/integration/prerequisites/support-and-troubleshoot/common-errors.md).

# Common Errors

This guide provides step-by-step solutions for the most frequently encountered errors when integrating with Oten IDP.

> 📖 **Error Reference**: See [Error Codes Reference](broken://pages/bJ3yHAB6ah0s2qAer3PL) for complete error documentation. 📖 **Implementation Guide**: See [OAuth Error Handling](https://gitlab.silvertiger.tech/documents/idp/-/blob/main/best-practices/oauth-error-handling.md) for code examples.

## 🎯 How to Use This Guide

Each error includes:

* **Symptoms** and when the error occurs
* **Root causes** and why it happens
* **Step-by-step solutions** to resolve the issue
* **Prevention tips** to avoid the error in the future
* **Working code examples** showing correct implementation

## 🔍 Quick Error Lookup

| Error Code               | Common Cause                             | Quick Fix                                               |
| ------------------------ | ---------------------------------------- | ------------------------------------------------------- |
| `invalid_request`        | Missing request parameter or JAR expired | [Implement/Fix JAR](#error-invalid_request)             |
| `invalid_request_object` | Invalid JAR signature/format             | [Fix JAR implementation](#error-invalid_request_object) |
| `invalid_grant`          | Code expired/used/invalid                | [Restart auth flow](#error-invalid_grant)               |
| `invalid_client`         | Wrong credentials or IP not whitelisted  | [Check client config](#error-invalid_client)            |
| `unauthorized_client`    | Public client using client\_credentials  | [Use confidential client](#error-unauthorized_client)   |
| `access_denied`          | User denied access                       | [Handle user denial](#error-access_denied)              |

## 🚨 Critical JAR-Related Errors

### Error: "invalid\_request" (Missing Request Parameter) <a href="#error-invalid_request" id="error-invalid_request"></a>

**When it occurs**: Authorization endpoint rejects requests without required request parameter

#### Error Response Format

```
HTTP/1.1 302 Found
Location: https://yourapp.com/callback?
  error=invalid_request&
  error_description=Request%20parameter%20is%20required&
  state=xyz789
```

#### Symptoms

* Authorization request fails immediately with 400 error
* User gets redirected to callback URL with error parameters
* Error code: `invalid_request`
* Error description: **"Request parameter is required"**
* Missing `request` parameter when `request_uri` not provided

#### Root Cause

Oten IDP **requires either `request` OR `request_uri` parameter** for all authorization requests (RFC 9101). When neither parameter is provided, you get "Request parameter is required" error.

#### Step-by-Step Solution

**Step 1: Identify the problem**

```javascript
// ❌ This approach will ALWAYS fail with Oten IDP
const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectURI}&response_type=code&scope=openid profile email&state=${state}`;
// Missing required 'request' parameter
```

**Step 2: Understand JAR requirement**

```javascript
// Oten IDP requires either:
// Option 1: request parameter (JWT-Secured Authorization Request)
// Option 2: request_uri parameter (URL pointing to JAR)
// You CANNOT provide both or neither

// ❌ Invalid - neither request nor request_uri
const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectURI}`;

// ❌ Invalid - both request and request_uri
const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=${clientId}&request=${jwt}&request_uri=${uri}`;
```

**Step 3: Implement JAR with request parameter**

```javascript
// ✅ Correct implementation with JAR
const jwt = require('jsonwebtoken');
const crypto = require('crypto');

function createJAR(authParams, clientSecret) {
  const now = Math.floor(Date.now() / 1000);

  const jarPayload = {
    // JWT Claims
    iss: authParams.client_id,
    aud: 'https://account.oten.com',
    iat: now,
    exp: now + 300, // 5 minutes
    jti: crypto.randomUUID(),

    // OAuth Parameters (ALL must be in JAR)
    client_id: authParams.client_id,
    redirect_uri: authParams.redirect_uri,
    response_type: 'code',
    scope: authParams.scope,
    state: authParams.state,
    code_challenge: authParams.code_challenge,
    code_challenge_method: 'S256'
  };

  return jwt.sign(jarPayload, clientSecret, { algorithm: 'HS256' });
}

// Usage
const authParams = {
  client_id: process.env.CLIENT_ID,
  redirect_uri: process.env.REDIRECT_URI,
  scope: 'openid profile email',
  state: generateState(),
  code_challenge: generateCodeChallenge(),
};

const requestJWT = createJAR(authParams, process.env.CLIENT_SECRET);
const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=${authParams.client_id}&request=${requestJWT}`;
```

**Step 3: Verify implementation**

* Check that authorization URL only contains `client_id` and `request` parameters
* Verify JAR contains all OAuth parameters in JWT payload
* Test with a real authorization request

#### Prevention Tips

* **Always include request parameter** - it's required for Oten IDP
* **Include ALL OAuth parameters** in JAR payload, not URL
* **Set appropriate expiration** (max 5 minutes)
* See [JAR Complete Guide](broken://pages/Dh6xDgKUfcwFtlZAntPO) for detailed implementation

#### Alternative for Legacy Applications

If your application cannot implement JAR due to technical constraints, contact <support@oten.dev> to discuss enabling traditional OAuth flow as a temporary solution.

**Include in your request:**

* Application details and technical constraints
* Reason why JAR cannot be implemented
* Security measures you have in place

### Error: "invalid\_request\_object" <a href="#error-invalid_request_object" id="error-invalid_request_object"></a>

**When it occurs**: JAR token has invalid format or signature

#### Error Response Format

```
HTTP/1.1 302 Found
Location: https://yourapp.com/callback?
  error=invalid_request_object&
  error_description=Invalid%20Request%20Object%3A%20JWT%20signature%20verification%20failed&
  state=xyz789
```

#### Symptoms

* Authorization request fails with 400 error
* User gets redirected to callback URL with error parameters
* Error code: `invalid_request_object`
* JAR token is created but rejected by Oten IDP

#### Root Causes

1. **Invalid JWT signature** - wrong client secret or private key
2. **Unsupported signing algorithm** - must be HS256 or EdDSA
3. **Malformed JWT structure** - invalid JWT format
4. **Missing or incorrect Key ID** (for EdDSA)
5. **Unregistered public key** (for EdDSA)

#### Step-by-Step Solution

**Step 1: Verify JWT structure**

```javascript
// Check if your JAR is valid JWT format
const jwtParts = requestJWT.split('.');
if (jwtParts.length !== 3) {
  console.error('Invalid JWT format - must have 3 parts separated by dots');
}

// Decode and inspect (without verification)
const header = JSON.parse(atob(jwtParts[0]));
const payload = JSON.parse(atob(jwtParts[1]));

console.log('JWT Header:', header);
console.log('JWT Payload:', payload);
```

**Step 2: Fix HS256 signature issues**

```javascript
// ✅ Correct HS256 implementation
const jwt = require('jsonwebtoken');

function createJAR_HS256(jarPayload, clientSecret) {
  // Ensure algorithm is exactly 'HS256'
  return jwt.sign(jarPayload, clientSecret, {
    algorithm: 'HS256',
    // Don't include keyid for HS256
  });
}

// Common mistakes to avoid:
// ❌ Wrong algorithm
// jwt.sign(payload, secret, { algorithm: 'RS256' }); // Not supported
// ❌ Wrong secret format
// jwt.sign(payload, Buffer.from(secret, 'base64')); // Use string directly
```

**Step 3: Fix EdDSA signature issues**

```javascript
// ✅ Correct EdDSA implementation
const fs = require('fs');

function createJAR_EdDSA(jarPayload, privateKeyPath, keyId) {
  const privateKey = fs.readFileSync(privateKeyPath, 'utf8');

  return jwt.sign(jarPayload, privateKey, {
    algorithm: 'EdDSA',
    keyid: keyId // Required for EdDSA
  });
}

// Verify your private key format
const privateKey = fs.readFileSync('private-key.pem', 'utf8');
if (!privateKey.includes('BEGIN PRIVATE KEY')) {
  console.error('Private key must be in PEM format');
}
```

**Step 4: Validate JAR payload (Confidential Clients Only)**

```javascript
// Note: JAR is only required for confidential clients
// Public clients should use PKCE with direct parameters instead

// Ensure all required claims are present
function validateJARPayload(payload) {
  const requiredClaims = ['iss', 'aud', 'iat', 'exp', 'jti'];
  const requiredOAuthParams = ['client_id', 'redirect_uri', 'response_type'];

  const missing = [...requiredClaims, ...requiredOAuthParams]
    .filter(claim => !payload[claim]);

  if (missing.length > 0) {
    throw new Error(`Missing required claims: ${missing.join(', ')}`);
  }

  // Validate timing
  const now = Math.floor(Date.now() / 1000);
  if (payload.exp <= now) {
    throw new Error('JAR token expired');
  }

  if (payload.iat > now + 60) {
    throw new Error('JAR issued in future');
  }
}
```

#### Prevention Tips

* **Use correct client secret** from Oten registration
* **Only use HS256 or EdDSA algorithms**
* **Include keyid for EdDSA** but not for HS256
* **Validate JAR payload** before signing
* **Test JAR creation** with a JWT debugger

### Error: "invalid\_request" (JAR Expired) <a href="#error-jar_expired" id="error-jar_expired"></a>

**When it occurs**: JAR token has exceeded its expiration time

#### Error Response Format

```
HTTP/1.1 302 Found
Location: https://yourapp.com/callback?
  error=invalid_request&
  error_description=JAR%20token%20has%20expired&
  state=xyz789
```

#### Symptoms

* Authorization request fails with 400 error
* Error code: `invalid_request`
* Error description mentions JAR expiration
* JAR was created more than 5 minutes ago

#### Root Cause

JAR tokens have a maximum lifetime of 5 minutes for security reasons.

#### Step-by-Step Solution

**Step 1: Check JAR expiration**

```javascript
// Decode JAR to check expiration
const jwtParts = requestJWT.split('.');
const payload = JSON.parse(atob(jwtParts[1]));

const now = Math.floor(Date.now() / 1000);
const expiresAt = payload.exp;
const issuedAt = payload.iat;

console.log('Current time:', now);
console.log('JAR issued at:', issuedAt);
console.log('JAR expires at:', expiresAt);
console.log('JAR age (seconds):', now - issuedAt);
console.log('Time until expiry (seconds):', expiresAt - now);

if (expiresAt <= now) {
  console.error('JAR has expired');
}
```

**Step 2: Generate fresh JAR**

```javascript
// ✅ Always generate JAR just before use
function createFreshJAR(authParams, clientSecret) {
  const now = Math.floor(Date.now() / 1000);

  const jarPayload = {
    // JWT Claims
    iss: authParams.client_id,
    aud: 'https://account.oten.com',
    iat: now,
    exp: now + 300, // 5 minutes from now
    jti: crypto.randomUUID(),

    // OAuth Parameters
    ...authParams
  };

  return jwt.sign(jarPayload, clientSecret, { algorithm: 'HS256' });
}

// Generate JAR immediately before redirect
const requestJWT = createFreshJAR(authParams, clientSecret);
const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=${clientId}&request=${requestJWT}`;

// Redirect immediately
res.redirect(authURL);
```

#### Prevention Tips

* **Generate JAR just before use** - don't pre-generate
* **Set expiration to 5 minutes maximum**
* **Don't cache JAR tokens**
* **Implement automatic retry** with fresh JAR if expired

## Token Endpoint Errors

### Error: "invalid\_grant" <a href="#error-invalid_grant" id="error-invalid_grant"></a>

**When it occurs**: Authorization code or refresh token is invalid

#### Error Response Format

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

{
  "error": "invalid_grant",
  "error_description": "Invalid authorization code: code not found"
}
```

#### Symptoms

* Token exchange fails with 400 error
* Error code: `invalid_grant`
* Various error descriptions depending on specific issue

#### Common Scenarios

**Scenario 1: Authorization code not found**

```json
{
  "error": "invalid_grant",
  "error_description": "Invalid authorization code: code not found"
}
```

**Scenario 2: Authorization code already used**

```json
{
  "error": "invalid_grant",
  "error_description": "Invalid authorization code: code already used"
}
```

**Scenario 3: Authorization code expired**

```json
{
  "error": "invalid_grant",
  "error_description": "Invalid authorization code: code expired"
}
```

**Scenario 4: PKCE verification failed**

```json
{
  "error": "invalid_grant",
  "error_description": "Invalid code verifier"
}
```

#### Step-by-Step Solution

**Step 1: Check authorization code**

```javascript
// Verify you're using the code from callback
app.get('/callback', (req, res) => {
  const { code, state, error } = req.query;

  if (error) {
    return handleAuthError(error, req, res);
  }

  if (!code) {
    return res.status(400).send('Missing authorization code');
  }

  // Use code immediately - don't store it
  exchangeCodeForTokens(code, req.session.codeVerifier);
});
```

**Step 2: Verify PKCE parameters**

```javascript
// Ensure code_verifier matches code_challenge
async function exchangeCodeForTokens(code, codeVerifier) {
  const tokenRequest = {
    grant_type: 'authorization_code',
    code: code,
    redirect_uri: process.env.REDIRECT_URI,
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    code_verifier: codeVerifier // Must match original code_challenge
  };

  const response = await fetch('/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams(tokenRequest)
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Token exchange failed: ${error.error_description}`);
  }

  return await response.json();
}
```

#### Prevention Tips

* **Use authorization code immediately** after receiving it
* **Don't reuse authorization codes** - they're single-use
* **Verify PKCE code\_verifier** matches original code\_challenge
* **Check redirect\_uri** matches exactly
* **Handle token exchange errors** gracefully

### Error: "invalid\_client" <a href="#error-invalid_client" id="error-invalid_client"></a>

**When it occurs**: Client authentication failed

#### Error Response Format

```json
HTTP/1.1 401 Unauthorized
Content-Type: application/json

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

#### Symptoms

* Token exchange fails with 401 error
* Error code: `invalid_client`
* Client credentials are rejected

#### Root Causes

1. **Wrong client\_id** - doesn't match registration
2. **Wrong client\_secret** - incorrect or missing
3. **Client not found** - client\_id not registered
4. **Wrong authentication method** - using wrong auth method
5. **IP address not whitelisted** - for client\_credentials grant
6. **Client not confidential** - public client attempting client\_credentials

#### Step-by-Step Solution

**Step 1: Verify client credentials**

```javascript
// Check your environment variables
console.log('Client ID:', process.env.CLIENT_ID);
console.log('Client Secret exists:', !!process.env.CLIENT_SECRET);
console.log('Client Secret length:', process.env.CLIENT_SECRET?.length);

// Verify against Oten registration
if (!process.env.CLIENT_ID || !process.env.CLIENT_SECRET) {
  throw new Error('Missing client credentials in environment variables');
}
```

**Step 2: Check authentication method**

```javascript
// ✅ Correct client authentication (client_secret_post)
const tokenRequest = {
  grant_type: 'authorization_code',
  code: authorizationCode,
  redirect_uri: process.env.REDIRECT_URI,
  client_id: process.env.CLIENT_ID,
  client_secret: process.env.CLIENT_SECRET // Include in body
};

// ❌ Don't use Basic authentication
// const auth = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
// headers: { 'Authorization': `Basic ${auth}` } // Not supported
```

**Step 3: Check IP whitelist (for client\_credentials grant)**

```javascript
// If using client_credentials grant and getting IP errors
if (grantType === 'client_credentials') {
  // Check your current IP
  const response = await fetch('https://api.ipify.org?format=json');
  const { ip } = await response.json();
  console.log('Current IP:', ip);

  // Verify IP is in Oten client whitelist
  // Contact Oten support to add IP to whitelist
}

// Example error response for IP not in whitelist:
// {
//   "error": "invalid_client",
//   "error_description": "Invalid client IP: 192.168.1.100 is not in whitelist"
// }
```

**Step 4: Verify client type (for client\_credentials grant)**

```javascript
// ✅ Client credentials grant requires confidential client
if (grantType === 'client_credentials') {
  // Ensure your client is registered as "confidential" not "public"
  // Public clients cannot use client_credentials grant

  const tokenRequest = {
    grant_type: 'client_credentials',
    client_id: process.env.CLIENT_ID, // Must be confidential client
    client_secret: process.env.CLIENT_SECRET, // Required for confidential clients
    scope: 'read:data write:data'
  };
}
```

#### Prevention Tips

* **Double-check client credentials** from Oten registration
* **Use client\_secret\_post** authentication method
* **Store credentials securely** in environment variables
* **Test with curl** to verify credentials work
* **Check IP whitelist** for client\_credentials grant
* **Verify client type** (confidential vs public)

### Error: "unauthorized\_client" <a href="#error-unauthorized_client" id="error-unauthorized_client"></a>

**When it occurs**: Client not authorized for the requested grant type

#### Error Response Format

```json
HTTP/1.1 403 Forbidden
Content-Type: application/json

{
  "error": "unauthorized_client",
  "error_description": "Public clients are not authorized for client credentials grant"
}
```

#### Symptoms

* Token exchange fails with 403 error
* Error code: `unauthorized_client`
* Specific to client\_credentials grant type

#### Root Cause

Public clients cannot use the client\_credentials grant type - only confidential clients are authorized.

#### Step-by-Step Solution

**Step 1: Check client type**

```javascript
// Verify your client registration type
console.log('Client ID:', process.env.CLIENT_ID);
console.log('Grant type:', 'client_credentials');

// Check if you have a client secret (confidential clients only)
if (!process.env.CLIENT_SECRET) {
  console.error('Missing client secret - this indicates a public client');
  console.error('Public clients cannot use client_credentials grant');
}
```

**Step 2: Use correct grant type for client type**

```javascript
// ✅ For public clients - use authorization_code with PKCE
if (clientType === 'public') {
  const tokenRequest = {
    grant_type: 'authorization_code',
    code: authorizationCode,
    redirect_uri: process.env.REDIRECT_URI,
    client_id: process.env.CLIENT_ID,
    code_verifier: codeVerifier // PKCE required for public clients
  };
}

// ✅ For confidential clients - can use client_credentials
if (clientType === 'confidential') {
  const tokenRequest = {
    grant_type: 'client_credentials',
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    scope: 'read:data'
  };
}
```

**Step 3: Register confidential client if needed**

```javascript
// If you need machine-to-machine authentication:
// 1. Register a new confidential client in Oten
// 2. Get client_id and client_secret
// 3. Configure IP whitelist if required
// 4. Use client_credentials grant

const confidentialClientConfig = {
  client_id: 'your_confidential_client_id',
  client_secret: 'your_confidential_client_secret',
  client_type: 'confidential',
  grant_types: ['client_credentials'],
  ip_whitelist: ['192.168.1.100', '10.0.0.50'] // Optional
};
```

#### Prevention Tips

* **Use correct client type** for your use case
* **Public clients**: Use authorization\_code with PKCE
* **Confidential clients**: Can use client\_credentials for M2M
* **Check client registration** in Oten admin portal

### Error: "invalid\_client" (IP Not Whitelisted) <a href="#error-ip_not_whitelisted" id="error-ip_not_whitelisted"></a>

**When it occurs**: Client credentials grant from non-whitelisted IP address

#### Error Response Format

```json
HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "error": "invalid_client",
  "error_description": "Invalid client IP: 192.168.1.100 is not in whitelist"
}
```

#### Symptoms

* Client credentials grant fails with 401 error
* Error code: `invalid_client`
* Error description mentions specific IP address
* Valid client credentials but request rejected

#### Root Cause

Oten IDP implements IP address validation for client credentials grant when IP whitelist is configured for enhanced security.

#### Step-by-Step Solution

**Step 1: Check your current IP address**

```javascript
// Check your current public IP
async function checkCurrentIP() {
  try {
    const response = await fetch('https://api.ipify.org?format=json');
    const { ip } = await response.json();
    console.log('Current public IP:', ip);
    return ip;
  } catch (error) {
    console.error('Failed to get IP:', error);
  }
}

// Check if IP is causing the issue
const currentIP = await checkCurrentIP();
console.log('If you see this IP in error message, it needs to be whitelisted:', currentIP);
```

**Step 2: Verify IP whitelist configuration**

```javascript
// Contact Oten support to:
// 1. Check if IP whitelist is configured for your client
// 2. Add your IP address to the whitelist
// 3. Verify whitelist configuration

// Example whitelist configuration:
const clientConfig = {
  client_id: 'your_client_id',
  client_type: 'confidential',
  ip_whitelist: [
    '192.168.1.100',    // Your current IP
    '10.0.0.50',        // Server IP
    '203.0.113.0/24'    // IP range (if supported)
  ]
};
```

**Step 3: Test from whitelisted IP**

```javascript
// After IP is added to whitelist, test the request
async function testClientCredentials() {
  const tokenRequest = {
    grant_type: 'client_credentials',
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    scope: 'read:data'
  };

  try {
    const response = await fetch('/oauth/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams(tokenRequest)
    });

    if (response.ok) {
      console.log('✅ IP whitelist validation passed');
      return await response.json();
    } else {
      const error = await response.json();
      console.error('❌ Still failing:', error);
    }
  } catch (error) {
    console.error('Network error:', error);
  }
}
```

#### Prevention Tips

* **Configure IP whitelist** in Oten admin portal
* **Use static IP addresses** for production servers
* **Document whitelisted IPs** for your team
* **Monitor IP changes** in your infrastructure
* **Test from all deployment environments**

#### Security Benefits

* Prevents unauthorized access even with valid credentials
* Provides additional layer of protection for machine-to-machine authentication
* Enables detection of credential theft or misuse from unexpected locations
* Supports compliance with network security policies

### Error: "access\_denied" <a href="#error-access_denied" id="error-access_denied"></a>

**When it occurs**: User denied authorization on consent screen

#### Error Response Format

```
HTTP/1.1 302 Found
Location: https://yourapp.com/callback?
  error=access_denied&
  error_description=The%20resource%20owner%20or%20authorization%20server%20denied%20the%20request&
  state=xyz789
```

#### Symptoms

* User gets redirected to callback with error
* Error code: `access_denied`
* User clicked "Deny" or "Cancel" on consent screen

#### Root Cause

This is normal user behavior - user chose not to grant access to your application.

#### Step-by-Step Solution

**Step 1: Handle gracefully**

```javascript
app.get('/callback', (req, res) => {
  const { error, error_description, state } = req.query;

  if (error === 'access_denied') {
    // This is normal - user denied access
    return res.render('access-denied', {
      message: 'You chose not to grant access to this application.',
      action: 'You can try again if you change your mind.',
      loginUrl: '/login'
    });
  }

  // Handle other errors...
});
```

**Step 2: Provide clear messaging**

```html
<!-- access-denied.html -->
<div class="error-message">
  <h2>Access Denied</h2>
  <p>You chose not to grant access to this application.</p>
  <p>If you change your mind, you can <a href="/login">try again</a>.</p>
</div>
```

#### Prevention Tips

* **Explain why you need permissions** before redirecting to auth
* **Request minimal scopes** - only what you actually need
* **Provide clear value proposition** to users
* **Handle denial gracefully** - don't show error messages

## 🌐 Network and Configuration Errors

### Error: "server\_error" <a href="#error-server_error" id="error-server_error"></a>

**When it occurs**: Internal server error on Oten IDP

#### Error Response Format

**Authorization Endpoint:**

```
HTTP/1.1 302 Found
Location: https://yourapp.com/callback?
  error=server_error&
  error_description=The%20authorization%20server%20encountered%20an%20unexpected%20condition&
  state=xyz789
```

**Token Endpoint:**

```json
HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "error": "server_error",
  "error_description": "The authorization server encountered an unexpected condition that prevented it from fulfilling the request"
}
```

#### Symptoms

* Intermittent failures
* Error code: `server_error`
* Usually temporary issues

#### Step-by-Step Solution

**Step 1: Implement retry logic**

```javascript
async function makeRequestWithRetry(requestFn, maxRetries = 3) {
  let lastError;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await requestFn();
    } catch (error) {
      lastError = error;

      // Only retry for server errors
      if (error.message.includes('server_error') && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
        console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      throw error;
    }
  }

  throw lastError;
}

// Usage for token exchange
const tokens = await makeRequestWithRetry(() =>
  exchangeCodeForTokens(code, codeVerifier)
);
```

**Step 2: Check Oten status**

```bash
# Check Oten service status
curl -I https://account.oten.com

# Check discovery endpoint
curl -s https://account.oten.com/.well-known/openid-configuration | jq .
```

#### Prevention Tips

* **Implement retry logic** with exponential backoff
* **Monitor Oten status page**
* **Set appropriate timeouts**
* **Log errors for investigation**

## 🔧 Quick Debugging Checklist

### Authorization Endpoint Issues

* [ ] Using JAR (not traditional OAuth parameters)
* [ ] JAR signature is valid (correct client secret/private key)
* [ ] JAR not expired (generated within 5 minutes)
* [ ] All required parameters in JAR payload
* [ ] Redirect URI matches registration exactly

### Token Endpoint Issues

* [ ] Authorization code used immediately
* [ ] Code not reused (single-use only)
* [ ] PKCE code\_verifier matches code\_challenge
* [ ] Client credentials are correct
* [ ] Using client\_secret\_post authentication
* [ ] Redirect URI matches authorization request
* [ ] **IP address in whitelist** (for client\_credentials grant)
* [ ] **Client is confidential** (for client\_credentials grant)
* [ ] **Correct grant type** for client type

### Network Issues

* [ ] HTTPS endpoints accessible
* [ ] No firewall blocking requests
* [ ] DNS resolution working
* [ ] Appropriate timeouts set
* [ ] Retry logic implemented

## 📚 Additional Resources

* [**Error Codes Reference**](broken://pages/bJ3yHAB6ah0s2qAer3PL): Complete error documentation
* [**JAR Implementation Guide**](broken://pages/Dh6xDgKUfcwFtlZAntPO): Detailed JAR examples
* [**API Reference**](broken://pages/rBfeuN3JiwHAXoU2ybbc): Complete API documentation
* [**Security Best Practices**](broken://pages/9YmJ1SYdIDChDe4DceZt): Security guidelines

***

**Need Help?** Contact Oten support at <support@oten.dev>
