Skip to content
oauth-implementation logo

Oauth Implementation

oauth-implementation

Load when implementing OAuth 2.0 and OpenID Connect authentication. Applies when building social login, SSO, PKCE flows, or integrating with OAuth providers like Google, GitHub, Apple.

telum-ai/speck0installs2starsSecurity

SKILL.md

Full skill instructions

OAuth 2.0 Flows

Flow Selection

FlowUse CaseSecurity
Authorization Code + PKCESPAs, mobile appsBest
Authorization CodeServer-side appsGood
Client CredentialsMachine-to-machineN/​A (no user)
ImplicitDeprecatedAvoid

PKCE (Proof Key for Code Exchange)

Required for public clients (SPAs, mobile). Prevents authorization code interception.

// 1. Generate code verifier (random string)
function generateCodeVerifier(): string {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return base64UrlEncode(array);
}

// 2. Create code challenge (SHA-256 hash)
async function generateCodeChallenge(verifier: string): Promise<string> {
  const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
  return base64UrlEncode(new Uint8Array(hash));
}

// 3. Store verifier in session, send challenge to auth server
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
sessionStorage.setItem('code_verifier', codeVerifier);

// Authorization URL
const authUrl = `https://auth.provider.com/​authorize?
  response_type=code&
  client_id=${clientId}&
  redirect_uri=${redirectUri}&
  scope=openid profile email&
  state=${generateState()}&
  code_challenge=${codeChallenge}&
  code_challenge_method=S256`;

Token Exchange

Exchange Code for Tokens

async function exchangeCodeForTokens(code: string): Promise<TokenResponse> {
  const codeVerifier = sessionStorage.getItem('code_verifier');
  
  const response = await fetch('https://auth.provider.com/​token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/​x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code,
      redirect_uri: redirectUri,
      client_id: clientId,
      code_verifier: codeVerifier!, // PKCE
    }),
  });
  
  return response.json();
}

interface TokenResponse {
  access_token: string;
  refresh_token?: string;
  id_token?: string;  // OpenID Connect
  token_type: 'Bearer';
  expires_in: number;
}

Token Refresh

Refresh Before Expiry

class TokenManager {
  private accessToken: string;
  private refreshToken: string;
  private expiresAt: number;
  
  async getValidToken(): Promise<string> {
    // Refresh if expires within 5 minutes
    if (Date.now() >= this.expiresAt - 5 * 60 * 1000) {
      await this.refresh();
    }
    return this.accessToken;
  }
  
  private async refresh(): Promise<void> {
    const response = await fetch('https://auth.provider.com/​token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/​x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'refresh_token',
        refresh_token: this.refreshToken,
        client_id: clientId,
      }),
    });
    
    const tokens = await response.json();
    this.accessToken = tokens.access_token;
    this.expiresAt = Date.now() + tokens.expires_in * 1000;
    
    if (tokens.refresh_token) {
      this.refreshToken = tokens.refresh_token; // Rotation
    }
  }
}

Refresh Token Rotation

Some providers rotate refresh tokens on each use. Always store the new refresh token.


State Parameter (CSRF Protection)

// Generate cryptographically random state
function generateState(): string {
  const array = new Uint8Array(16);
  crypto.getRandomValues(array);
  return base64UrlEncode(array);
}

// Store before redirect
const state = generateState();
sessionStorage.setItem('oauth_state', state);

// Validate on callback
function validateCallback(urlState: string): boolean {
  const storedState = sessionStorage.getItem('oauth_state');
  sessionStorage.removeItem('oauth_state');
  return urlState === storedState;
}

OpenID Connect (OIDC)

ID Token Validation

import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';

const client = jwksClient({
  jwksUri: 'https://auth.provider.com/​.well-known/​jwks.json',
});

async function validateIdToken(idToken: string): Promise<IdTokenPayload> {
  const decoded = jwt.decode(idToken, { complete: true });
  const key = await client.getSigningKey(decoded.header.kid);
  
  return jwt.verify(idToken, key.getPublicKey(), {
    audience: clientId,
    issuer: 'https://auth.provider.com',
    algorithms: ['RS256'],
  }) as IdTokenPayload;
}

interface IdTokenPayload {
  sub: string;      // User ID
  email: string;
  email_verified: boolean;
  name: string;
  picture?: string;
  iat: number;
  exp: number;
}

Provider-Specific Gotchas

Google

// Prompt for consent every time (useful for testing)
const authUrl = `https://accounts.google.com/​o/​oauth2/​v2/​auth?
  ...
  prompt=consent&
  access_type=offline`;  // Required for refresh token

Gotcha: Google only returns refresh_token on first authorization. Use prompt=consent to force it again.

GitHub

Gotcha: GitHub access tokens don't expire by default. Consider using GitHub Apps with short-lived tokens.

Apple

Gotcha: Apple only sends user info (name, email) on FIRST login. Store it immediately.

// Apple returns user info in POST body, not in ID token
const { user } = req.body; // { name: { firstName, lastName }, email }

Microsoft/​Azure AD

Gotcha: Different endpoints for personal vs. work accounts:

  • Personal: https://login.microsoftonline.com/​consumers
  • Work: https://login.microsoftonline.com/​{tenant}
  • Both: https://login.microsoftonline.com/​common

Token Storage

Where to Store Tokens

TokenStorageNotes
Access TokenMemoryShort-lived, OK in memory
Refresh TokenHttpOnly CookieNever expose to JS
ID TokenMemory or localStorageVerify signature before use

Backend Token Proxy Pattern

// Frontend never sees tokens
// Backend stores tokens, proxies API calls

// POST /​api/​auth/​callback
app.post('/​api/​auth/​callback', async (req, res) => {
  const tokens = await exchangeCode(req.body.code);
  
  // Store tokens server-side
  await saveTokens(req.session.userId, tokens);
  
  res.json({ success: true });
});

// POST /​api/​proxy/​github
app.post('/​api/​proxy/​github', async (req, res) => {
  const tokens = await getTokens(req.session.userId);
  
  const response = await fetch('https://api.github.com' + req.body.path, {
    headers: { Authorization: `Bearer ${tokens.access_token}` },
  });
  
  res.json(await response.json());
});

Common Gotchas

Redirect URI Mismatch

Must match exactly (including trailing slashes, http vs https).

Scope Changes

If you request new scopes, user must re-consent. Some providers require prompt=consent.

Token Expiry Race Conditions

Multiple concurrent requests might all try to refresh. Use a mutex or single refresh queue.

CORS on Token Endpoint

Token endpoint often doesn't support CORS. Exchange tokens server-side.

Silent Refresh Failures

Use hidden iframe for silent refresh, but handle third-party cookie blocks gracefully.


Quick Reference

TaskPattern
PKCE flowGenerate verifier → hash to challenge → exchange with verifier
CSRF protectionRandom state → store → validate on callback
Token refreshRefresh 5 min before expiry
Store refresh tokenHttpOnly cookie or server-side
Validate ID tokenCheck signature, aud, iss, exp

References

More Security skills

supabase logo
Security

supabase

Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...

2.7K 308.9K
View

Comprehensive guides and best practices for Neon Serverless Postgres, covering setup, connection methods, authentication, and platform APIs.

98 216.2K
View

Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.

462 163.8K
View

A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.

462 127.7K
View

Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.

462 125.1K
View

Complete Better Auth server and client setup with database adapters, session management, plugins, and security configuration.

222 118.2K
View

Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".

31.9K 116.1K
View
cloudflare logo
Security

cloudflare

Complete Cloudflare platform integration with decision trees for compute, storage, AI, networking, security, and infrastructure-as-code.

3K 110.7K
View

Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.

253 103K
View
gws-gmail logo
Security

gws-gmail

Send, read, and manage Gmail messages, drafts, labels, and account settings.

31.2K 78.9K
View

Comprehensive website auditing across 230+ rules in 21 categories including SEO, performance, security, and accessibility.

94 72.3K
View
gws-shared logo
Security

gws-shared

Shared authentication, CLI syntax, and output formatting patterns for gws Google Workspace commands.

31.2K 63.4K
View

Security AI tools

StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
GeoSpy logo
Security

GeoSpy

GeoSpy: Pricing, Features, FAQs, and Alternatives for AI Teams

Free
View

Detect AI-generated voices to protect against audio fraud.

Paid
View

Ensure Your Content's Originality with AI Plagiarism Checker

Freemium
View
Img Upscaler logo
Security

Img Upscaler

Upscale images by 400% without quality loss

Freemium
View
AICheatCheck logo
Security

AICheatCheck

Accurately Detect AI-Generated Content with TheChecker.AI

Free
View
D
Security

Detect GPT

Chrome extension that detects and flags AI-generated content

Free
View