# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://oten.gitbook.io/identity-support/integration/prerequisites/support-and-troubleshoot/common-errors.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
