Troubleshooting Guide

Common issues and solutions for OpenDev platform integration.


Authentication Issues

Issue: OAuth Login Fails with "Invalid Client"

Symptoms:

  • Error message: invalidclient or clientid is invalid
  • Login popup closes immediately

Solutions:

  1. Verify Client ID:
- Go to OpenDev Dashboard > Apps > Your App > OAuth Channels
   - Confirm the Client ID matches provider console
  1. Check Provider Console:
  • Ensure OAuth app is enabled/published
  • Verify redirect URIs are correctly configured
  • Check if app is in production mode (not test mode)
  1. For Google:
- Enable required APIs (Google+ API, People API)
   - Verify OAuth consent screen is configured
   - Add authorized domains

Issue: "Redirect URI Mismatch" Error

Symptoms:

  • Error: redirecturimismatch
  • Works in development but fails in production

Solutions:

  1. Check Exact Match:
Provider Console URI: https://yourdomain.com/auth/google/callback
   OpenDev Config URI:   https://yourdomain.com/auth/google/callback
   
   Note: Trailing slashes matter!
  1. Protocol Issues:
❌ http://yourdomain.com/callback  (No HTTPS)
   ✅ https://yourdomain.com/callback (HTTPS required in production)
  1. Multiple Environments:
// Development
   "callbackUrl": "http://localhost:3000/auth/google/callback"
   
   // Production  
   "callbackUrl": "https://yourdomain.com/auth/google/callback"

Issue: Apple Sign In Not Working on Web

Symptoms:

  • Popup appears but closes without completing
  • Error: invalid_request

Solutions:

  1. Service ID Configuration:
- Create separate Service ID for web (not App ID)
   - Configure domains and return URLs
   - Verify private key is associated with Service ID
  1. Domain Verification:
- Download apple-developer-domain-association.txt
   - Place at: https://yourdomain.com/.well-known/
   - Verify domain in Apple Developer Console
  1. Private Key Format:
- Must be PEM format with headers
   - Store securely (never in client code)
   - Check key hasn't expired

Payment Issues

Issue: Stripe Payment Intent Fails

Symptoms:

  • Error: paymentintentunexpected_state
  • Payment stuck in "processing"

Solutions:

  1. Check Payment Intent Status:
const intent = await stripe.paymentIntents.retrieve(intentId);
   console.log('Status:', intent.status);
   console.log('Last error:', intent.last_payment_error);
  1. Common Status Issues:
Status Meaning Action
requirespaymentmethod No payment method Collect payment details
requires_confirmation Needs confirmation Call confirmPayment()
requires_action 3D Secure needed Handle authentication
canceled Was cancelled Create new intent
  1. 3D Secure Handling:
if (intent.status === 'requires_action') {
       const { error } = await stripe.handleCardAction(intent.client_secret);
       if (error) {
           // Handle authentication failure
       }
   }

Issue: Google Play Purchase Not Verified

Symptoms:

  • Purchase succeeds on device but verification fails
  • Error: The purchase token does not match the package name

Solutions:

  1. Verify Package Name:
Package name in Play Console: com.yourcompany.app
   Package name in verification request: com.yourcompany.app
   
   These MUST match exactly
  1. Service Account Permissions:
1. Create service account in Google Cloud Console
   2. Add service account email to Play Console
   3. Grant "View financial data" permission
   4. Wait 24 hours for permissions to propagate
  1. Check Purchase Token:
// Token should be from purchase callback, not generated
   const purchaseToken = purchase.purchaseToken;  // ✅ Correct
   const purchaseToken = generateToken();          // ❌ Wrong

Issue: Apple IAP Receipt Verification Fails

Symptoms:

  • Status code 21007 or 21008
  • Error: shared_secret is invalid

Solutions:

  1. Sandbox vs Production:
// Status 21007 = Sandbox receipt sent to production
   // Solution: Try sandbox endpoint
   
   async function verifyReceipt(receipt) {
       let result = await verifyWithEndpoint(receipt, PRODUCTION_URL);
       if (result.status === 21007) {
           result = await verifyWithEndpoint(receipt, SANDBOX_URL);
       }
       return result;
   }
  1. Shared Secret:
1. Go to App Store Connect > Apps > Your App
   2. Features > In-App Purchases > App-Specific Shared Secret
   3. Generate and copy to OpenDev configuration
  1. Receipt Format:
// Receipt must be base64 encoded
   const receiptData = Buffer.from(receipt).toString('base64');

SDK Issues

Issue: SDK Initialization Fails

Symptoms:

  • Error: Invalid configuration
  • App crashes on startup

Solutions:

  1. Check Configuration File:
{
       "appId": "required",      // ✅ Must be valid UUID
       "channelId": "required",  // ✅ Must exist in OpenDev
       "environment": "production" // ✅ or "development"
   }
  1. Verify Network Access:
iOS: Add App Transport Security exceptions if needed
   Android: Add network permission to manifest
   Web: Check CORS configuration
  1. Debug Mode:
OpenDev.configure({
       appId: 'xxx',
       debug: true,
       onError: (error) => console.error('SDK Error:', error)
   });

Issue: Token Refresh Fails

Symptoms:

  • User gets logged out unexpectedly
  • Error: refreshtokeninvalid

Solutions:

  1. Check Token Storage:
// Ensure tokens are stored securely and not cleared
   const storedToken = await SecureStorage.get('refresh_token');
   if (!storedToken) {
       // Token was cleared - need to re-login
   }
  1. Token Expiration:
// Refresh tokens also expire (typically 30-90 days)
   // Implement proactive refresh before expiration
   
   const tokenExpiry = decodeToken(refreshToken).exp;
   const now = Date.now() / 1000;
   if (tokenExpiry - now < 86400) { // Less than 1 day
       await refreshAuthToken();
   }
  1. Provider-Specific Issues:
  • Google: Refresh tokens may be revoked if unused for 6 months
  • Apple: Refresh tokens require revalidation on privacy changes
  • WeChat: Tokens expire after 30 days regardless of usage

Network Issues

Issue: API Requests Timeout

Symptoms:

  • Requests hang indefinitely
  • Error: ETIMEDOUT or ECONNRESET

Solutions:

  1. Implement Timeouts:
const controller = new AbortController();
   const timeout = setTimeout(() => controller.abort(), 10000);
   
   try {
       const response = await fetch(url, {
           signal: controller.signal
       });
   } finally {
       clearTimeout(timeout);
   }
  1. Retry Logic:
async function fetchWithRetry(url, options, maxRetries = 3) {
       for (let i = 0; i < maxRetries; i++) {
           try {
               return await fetch(url, options);
           } catch (error) {
               if (i === maxRetries - 1) throw error;
               await sleep(Math.pow(2, i) * 1000); // Exponential backoff
           }
       }
   }
  1. Check Network Configuration:
- Verify firewall rules allow outbound HTTPS
   - Check proxy settings if behind corporate network
   - Test with different network (mobile data vs WiFi)

Issue: CORS Errors in Browser

Symptoms:

  • Error: Access-Control-Allow-Origin header missing
  • Requests work in Postman but not browser

Solutions:

  1. Verify Allowed Origins:
OpenDev Dashboard > Apps > Your App > Settings
   Add your domain to allowed origins:
   - https://yourdomain.com
   - http://localhost:3000 (for development)
  1. Preflight Requests:
// Ensure server handles OPTIONS requests
   // Check that all required CORS headers are present:
   // - Access-Control-Allow-Origin
   // - Access-Control-Allow-Methods
   // - Access-Control-Allow-Headers
  1. Credentials:
// If using cookies, both sides must allow credentials
   fetch(url, {
       credentials: 'include'  // Client side
   });
   
   // Server must return:
   // Access-Control-Allow-Credentials: true

Webhook Issues

Issue: Webhooks Not Being Received

Symptoms:

  • No webhook events in logs
  • Provider shows delivery failures

Solutions:

  1. Verify URL Accessibility:
# Test from external network
   curl -X POST https://yourdomain.com/webhooks/stripe \
        -H "Content-Type: application/json" \
        -d '{"test": true}'
  1. Check HTTPS Certificate:
- Certificate must be valid (not self-signed)
   - Certificate chain must be complete
   - Certificate must not be expired
  1. Firewall Rules:
- Allow incoming connections on port 443
   - Whitelist provider IP ranges if possible

Issue: Webhook Signature Verification Fails

Symptoms:

  • Error: Signature verification failed
  • Events processed but marked as invalid

Solutions:

  1. Raw Body Required:
// WRONG: Body already parsed
   app.use(express.json());
   app.post('/webhooks/stripe', (req, res) => {
       // req.body is object, not raw
   });
   
   // CORRECT: Raw body for verification
   app.post('/webhooks/stripe', 
       express.raw({ type: 'application/json' }),
       (req, res) => {
           // req.body is Buffer
       }
   );
  1. Secret Mismatch:
- Use webhook-specific secret (not API key)
   - Ensure secret is for correct environment (test vs live)
   - Don't confuse signing secret with endpoint secret
  1. Timestamp Tolerance:
// Webhooks have timestamp tolerance (usually 5 minutes)
   // Check server time is synchronized
   const tolerance = 300; // 5 minutes

Performance Issues

Issue: Slow API Responses

Symptoms:

  • Response times > 2 seconds
  • Intermittent timeouts

Solutions:

  1. Connection Pooling:
// Reuse HTTP connections
   const https = require('https');
   const agent = new https.Agent({ 
       keepAlive: true,
       maxSockets: 50
   });
  1. Caching:
// Cache configuration and static data
   const cache = new Map();
   
   async function getConfig() {
       if (cache.has('config')) {
           return cache.get('config');
       }
       const config = await fetchConfig();
       cache.set('config', config);
       return config;
   }
  1. Parallel Requests:
// Batch independent operations
   const [user, products, config] = await Promise.all([
       fetchUser(),
       fetchProducts(),
       fetchConfig()
   ]);

Getting Help

If you're still experiencing issues:

  1. Enable Debug Logging:
OpenDev.configure({
       debug: true,
       logLevel: 'verbose'
   });
  1. Collect Information:
  • SDK version
  • Platform and version
  • Error messages and stack traces
  • Steps to reproduce
  1. Contact Support:
  • Email: contact@zinben.com
  • Include debug logs and reproduction steps

Last updated: January 2026