Files
memory-infrastructure-palace/docs/projects/Pokedex.Online/api-reference/oauth-setup.md

9.6 KiB

Challonge OAuth Setup Guide

Complete guide to implementing OAuth authentication for Challonge API v2.1 APPLICATION scope.

Quick Start

Development Setup (5 minutes)

  1. Register OAuth Application

    • Visit https://connect.challonge.com
    • Create new application
    • Set redirect URI: http://localhost:5173/oauth/callback
    • Note your Client ID and Client Secret
  2. Configure Environment

    cp .env.example .env
    

    Edit .env:

    # Frontend (Vite variables)
    VITE_CHALLONGE_CLIENT_ID=your_client_id_here
    VITE_CHALLONGE_REDIRECT_URI=http://localhost:5173/oauth/callback
    
    # Backend (OAuth Proxy)
    CHALLONGE_CLIENT_ID=your_client_id_here
    CHALLONGE_CLIENT_SECRET=your_client_secret_here
    CHALLONGE_REDIRECT_URI=http://localhost:5173/oauth/callback
    OAUTH_PROXY_PORT=3001
    
  3. Install Dependencies

    npm install
    
  4. Run Development Servers

    # Option 1: Run both servers with one command
    npm run dev:full
    
    # Option 2: Run separately in two terminals
    # Terminal 1 - Frontend
    npm run dev
    
    # Terminal 2 - OAuth Proxy
    npm run oauth-proxy
    
  5. Test OAuth Flow

Architecture

┌─────────────────┐
│   Vue Frontend  │
│  localhost:5173 │
└────────┬────────┘
         │
         ├─→ User clicks "Connect with OAuth"
         │   Redirect to Challonge authorization URL
         │
         ├─→ User authorizes on Challonge
         │   Redirect back to /oauth/callback?code=xxx&state=yyy
         │
         ├─→ Frontend calls /api/oauth/token
         │
┌────────▼────────┐
│  OAuth Proxy    │
│  localhost:3001 │
└────────┬────────┘
         │
         ├─→ Exchange code for tokens (includes client_secret)
         │   POST https://api.challonge.com/oauth/token
         │
         └─→ Return tokens to frontend
             Frontend stores in localStorage
             Creates v2.1 client with Bearer token

Files Created

Backend

  • server/oauth-proxy.js - Express server for OAuth token exchange
    • /oauth/token - Exchange authorization code
    • /oauth/refresh - Refresh expired tokens
    • /health - Health check endpoint

Frontend

  • src/composables/useChallongeOAuth.js - OAuth state management

    • Token storage and retrieval
    • Authorization URL generation
    • Automatic token refresh
    • CSRF protection
  • src/views/OAuthCallback.vue - OAuth redirect handler

    • Processes authorization callback
    • Displays loading/success/error states
    • Auto-redirects to Challonge Test

Configuration

  • vite.config.js - Added /api/oauth proxy
  • src/router/index.js - Added /oauth/callback route
  • package.json - Added dependencies and scripts
  • .env.example - OAuth configuration template

Environment Variables

Frontend (Vite - PUBLIC)

VITE_CHALLONGE_CLIENT_ID=xxx        # OAuth Client ID (public)
VITE_CHALLONGE_REDIRECT_URI=xxx     # Callback URL

Backend (OAuth Proxy - PRIVATE)

CHALLONGE_CLIENT_ID=xxx             # OAuth Client ID
CHALLONGE_CLIENT_SECRET=xxx         # OAuth Client Secret (NEVER expose)
CHALLONGE_REDIRECT_URI=xxx          # Must match registered URL
OAUTH_PROXY_PORT=3001               # Proxy server port

Production (Optional)

NODE_ENV=production
FRONTEND_URL=https://yourdomain.com

Production Deployment

Option 1: Express Server (Simple)

Deploy server/oauth-proxy.js to:

  • Heroku
  • Railway
  • DigitalOcean App Platform
  • AWS EC2/ECS

Update production .env:

NODE_ENV=production
FRONTEND_URL=https://yourdomain.com
CHALLONGE_CLIENT_ID=xxx
CHALLONGE_CLIENT_SECRET=xxx
CHALLONGE_REDIRECT_URI=https://yourdomain.com/oauth/callback
PORT=3000

Update frontend build environment:

VITE_CHALLONGE_CLIENT_ID=xxx
VITE_CHALLONGE_REDIRECT_URI=https://yourdomain.com/oauth/callback

Option 2: Serverless Functions (Scalable)

Convert server/oauth-proxy.js to serverless functions:

Netlify Functions (netlify/functions/oauth-token.js):

import fetch from 'node-fetch';

export async function handler(event) {
  if (event.httpMethod !== 'POST') {
    return { statusCode: 405, body: 'Method Not Allowed' };
  }

  const { code } = JSON.parse(event.body);
  
  const response = await fetch('https://api.challonge.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: process.env.CHALLONGE_CLIENT_ID,
      client_secret: process.env.CHALLONGE_CLIENT_SECRET,
      code: code,
      redirect_uri: process.env.CHALLONGE_REDIRECT_URI,
    }),
  });

  const data = await response.json();
  
  return {
    statusCode: response.status,
    body: JSON.stringify(data),
  };
}

Vercel Functions (api/oauth/token.js):

import fetch from 'node-fetch';

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method Not Allowed' });
  }

  const { code } = req.body;
  
  const response = await fetch('https://api.challonge.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: process.env.CHALLONGE_CLIENT_ID,
      client_secret: process.env.CHALLONGE_CLIENT_SECRET,
      code: code,
      redirect_uri: process.env.CHALLONGE_REDIRECT_URI,
    }),
  });

  const data = await response.json();
  res.status(response.status).json(data);
}

Option 3: Cloudflare Workers (Edge)

export default {
  async fetch(request, env) {
    if (request.method !== 'POST') {
      return new Response('Method Not Allowed', { status: 405 });
    }

    const { code } = await request.json();
    
    const response = await fetch('https://api.challonge.com/oauth/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: env.CHALLONGE_CLIENT_ID,
        client_secret: env.CHALLONGE_CLIENT_SECRET,
        code: code,
        redirect_uri: env.CHALLONGE_REDIRECT_URI,
      }),
    });

    return response;
  }
};

Security Best Practices

DO

  • Store client_secret ONLY on backend (never in frontend)
  • Use HTTPS in production
  • Validate state parameter for CSRF protection
  • Store tokens in localStorage (XSS protection via CSP)
  • Set appropriate token expiration
  • Implement token refresh before expiration
  • Use environment variables for secrets

DON'T

  • Never commit .env to version control
  • Never expose client_secret in frontend code
  • Never log tokens in production
  • Don't use OAuth without SSL in production
  • Don't store tokens in cookies (CSRF risk)

Testing

Test OAuth Flow

  1. Start both servers: npm run dev:full
  2. Visit http://localhost:5173/challonge-test
  3. Click "Connect with OAuth"
  4. Should redirect to Challonge
  5. Authorize the app
  6. Should redirect back to callback
  7. Should see success message
  8. Should redirect to Challonge Test
  9. OAuth status should show "Connected"
  10. Try listing tournaments with "Show all tournaments" checked

Test Token Refresh

// In browser console after connecting
const { refreshToken } = useChallongeOAuth();
await refreshToken(); // Should refresh token

Test Logout

// In browser console
const { logout } = useChallongeOAuth();
logout(); // Should clear tokens

Troubleshooting

"Missing required environment variables"

  • Check .env file exists in project root
  • Verify CHALLONGE_CLIENT_ID and CHALLONGE_CLIENT_SECRET are set
  • Restart OAuth proxy after changing .env

"Invalid state parameter"

  • Clear browser storage and try again
  • Verify redirect URI matches exactly

"Token exchange failed"

  • Check client ID and secret are correct
  • Verify redirect URI matches registered URL exactly
  • Check OAuth proxy is running on port 3001
  • Look at OAuth proxy console for error details

"CORS errors"

  • Verify Vite proxy is configured correctly
  • Check OAuth proxy CORS settings
  • Ensure frontend URL is allowed in production

"Token expired"

  • Token should auto-refresh when needed
  • Manually refresh: useChallongeOAuth().refreshToken()
  • If refresh fails, user must re-authenticate

API Scopes

Available scopes for Challonge OAuth:

  • tournaments:read - Read tournament data
  • tournaments:write - Create/update tournaments
  • participants:read - Read participant data
  • participants:write - Manage participants
  • matches:read - Read match data
  • matches:write - Update match results
  • user:read - Read user profile

Default scope in app: tournaments:read tournaments:write

Next Steps

  1. Basic OAuth flow working
  2. Token storage and refresh
  3. APPLICATION scope access
  4. 🔄 Add scope selector in UI (optional)
  5. 🔄 Implement token refresh UI indicator
  6. 🔄 Add "time until expiration" display
  7. 🔄 Deploy to production
  8. 🔄 Add more scopes as needed

Support