Debug and Troubleshooting

This comprehensive guide helps you debug and troubleshoot Oten IDP integration issues systematically.

πŸ” Debugging Methodology

Step 1: Identify the Problem Area

OAuth Flow Stages:

  1. JAR Creation - Creating and signing JWT authorization request

  2. Authorization - Redirecting user to Oten IDP

  3. Callback - Handling authorization response

  4. Token Exchange - Converting authorization code to tokens

  5. API Calls - Using access tokens for API requests

Step 2: Gather Information

Before troubleshooting, collect:

  • Error messages (exact text and error codes)

  • HTTP status codes

  • Request/response headers

  • Timestamps

  • Environment (development/production)

  • Client configuration

Step 3: Use Debugging Tools

πŸ› οΈ Debugging Tools

1. JAR Token Decoder

Use this to inspect your JAR tokens:

// Decode JAR without verification (for debugging only)
function debugJAR(jarToken) {
  try {
    const decoded = jwt.decode(jarToken, { complete: true });

    console.log('=== JAR DEBUG INFO ===');
    console.log('Header:', JSON.stringify(decoded.header, null, 2));
    console.log('Payload:', JSON.stringify(decoded.payload, null, 2));

    // Check required claims
    const required = ['iss', 'aud', 'iat', 'exp', 'jti', 'client_id', 'redirect_uri', 'response_type'];
    const missing = required.filter(claim => !decoded.payload[claim]);

    if (missing.length > 0) {
      console.log('❌ Missing required claims:', missing);
    } else {
      console.log('βœ… All required claims present');
    }

    // Check expiration
    const now = Math.floor(Date.now() / 1000);
    if (decoded.payload.exp < now) {
      console.log('❌ Token expired');
    } else {
      console.log('βœ… Token not expired');
    }

    // Check audience
    if (decoded.payload.aud !== 'https://account.oten.com' &&
        decoded.payload.aud !== 'https://account.sbx.oten.dev') {
      console.log('❌ Invalid audience');
    } else {
      console.log('βœ… Valid audience');
    }

  } catch (error) {
    console.log('❌ Failed to decode JAR:', error.message);
  }
}

// Usage
debugJAR(yourJARToken);

2. Environment Checker

Verify your environment configuration:

function checkEnvironment() {
  console.log('=== ENVIRONMENT CHECK ===');

  const required = [
    'OTEN_CLIENT_ID',
    'OTEN_REDIRECT_URI'
  ];

  const optional = [
    'OTEN_CLIENT_SECRET',
    'OTEN_PRIVATE_KEY_PATH',
    'OTEN_KEY_ID',
    'OTEN_ENV'
  ];

  console.log('Required variables:');
  required.forEach(key => {
    const value = process.env[key];
    console.log(`  ${key}: ${value ? 'βœ… Set' : '❌ Missing'}`);
  });

  console.log('Optional variables:');
  optional.forEach(key => {
    const value = process.env[key];
    console.log(`  ${key}: ${value ? 'βœ… Set' : '⚠️ Not set'}`);
  });

  // Check redirect URI format
  const redirectUri = process.env.OTEN_REDIRECT_URI;
  if (redirectUri) {
    if (redirectUri.startsWith('https://') || redirectUri.startsWith('http://localhost')) {
      console.log('βœ… Redirect URI format valid');
    } else {
      console.log('❌ Redirect URI must use HTTPS (or http://localhost for development)');
    }
  }
}

3. Quick Connectivity Test

Test basic connectivity to Oten IDP:

# Test basic connectivity
curl -I https://account.oten.com

# Test discovery endpoint
curl https://account.oten.com/.well-known/openid_configuration

# Test JWKS endpoint
curl https://account.oten.com/.well-known/jwks.json

Step-by-Step Troubleshooting

Problem: "Cannot connect to Oten IDP"

Symptoms:

  • Network timeouts

  • Connection refused errors

  • DNS resolution failures

Solutions:

  1. Check network connectivity:

# Test basic connectivity
ping account.oten.com

# Test HTTPS connectivity
curl -I https://account.oten.com
  1. Verify firewall settings:

  • Ensure outbound HTTPS (port 443) is allowed

  • Check corporate firewall/proxy settings

  • Verify no SSL/TLS inspection is interfering

  1. Check DNS resolution:

nslookup account.oten.com

Problem: "JAR signature verification failed"

Symptoms:

  • Error code: invalid_request_object

  • Authorization request rejected

Solutions:

  1. For HS256 issues:

// Verify client secret
console.log('Client secret length:', process.env.OTEN_CLIENT_SECRET?.length);

// Test JAR creation
const testPayload = { test: 'data', iat: Math.floor(Date.now() / 1000) };
try {
  const testJWT = jwt.sign(testPayload, process.env.OTEN_CLIENT_SECRET, { algorithm: 'HS256' });
  console.log('βœ… JWT signing works');

  // Verify locally
  const verified = jwt.verify(testJWT, process.env.OTEN_CLIENT_SECRET, { algorithm: 'HS256' });
  console.log('βœ… JWT verification works');
} catch (error) {
  console.log('❌ JWT signing/verification failed:', error.message);
}
  1. For EdDSA issues:

// Check private key format
const fs = require('fs');
try {
  const privateKey = fs.readFileSync(process.env.OTEN_PRIVATE_KEY_PATH, 'utf8');
  console.log('βœ… Private key file readable');

  if (privateKey.includes('BEGIN PRIVATE KEY')) {
    console.log('βœ… Private key format appears correct');
  } else {
    console.log('⚠️ Private key format may be incorrect');
  }
} catch (error) {
  console.log('❌ Cannot read private key file:', error.message);
}

// Verify Key ID is set
if (process.env.OTEN_KEY_ID) {
  console.log('βœ… Key ID is set:', process.env.OTEN_KEY_ID);
} else {
  console.log('❌ Key ID is not set');
}

Problem: "Token exchange fails"

Symptoms:

  • Error code: invalid_grant

  • Authorization code rejected

Solutions:

  1. Check authorization code:

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

  console.log('Authorization code length:', code?.length);
  console.log('State matches:', state === storedState);

  if (!code) {
    console.log('❌ No authorization code received');
    return;
  }

  if (code.length < 10) {
    console.log('❌ Authorization code seems too short');
    return;
  }

  console.log('βœ… Authorization code appears valid');
});
  1. Verify PKCE parameters:

// Ensure code_verifier matches code_challenge
const storedVerifier = session.codeVerifier;
const challengeFromVerifier = crypto
  .createHash('sha256')
  .update(storedVerifier)
  .digest('base64url');

console.log('Stored verifier:', storedVerifier);
console.log('Challenge from verifier:', challengeFromVerifier);
console.log('Original challenge:', session.codeChallenge);
console.log('Challenges match:', challengeFromVerifier === session.codeChallenge);
  1. Check redirect URI:

// Ensure redirect URI exactly matches registration
const configuredURI = process.env.OTEN_REDIRECT_URI;
const requestURI = req.get('host') + req.originalUrl.split('?')[0];

console.log('Configured redirect URI:', configuredURI);
console.log('Actual request URI:', requestURI);
console.log('URIs match:', configuredURI.includes(requestURI));

Troubleshooting Checklist

Before Contacting Support

Complete this checklist before reaching out for help:

Environment Setup:

JAR Implementation:

OAuth Flow:

Error Information Collected:

πŸ†˜ Getting Help

If you've completed the troubleshooting checklist and still need help:

Contact Support

Technical Support: [email protected]

Include This Information

When contacting support, please include:

  1. Environment details:

    • Development or production

    • Programming language and version

    • Library versions used

  2. Error information:

    • Complete error message

    • Error code and HTTP status

    • Timestamp of the error

  3. Configuration (sanitized):

    • Client ID (safe to share)

    • Redirect URI

    • Scopes requested

    • JAR signing method used

  4. Code samples:

    • JAR creation code (remove secrets)

    • Authorization URL generation

    • Token exchange implementation

  5. Debugging output:

    • JAR token structure (decoded)

    • Network request/response logs

    • Environment check results

What NOT to Share

Never share these in support requests:

  • Client secrets

  • Private keys

  • Access tokens

  • Refresh tokens

  • User credentials

Last updated