/** * PKCE (Proof Key for Code Exchange) utilities. * Uses the Web Crypto API — no external dependencies needed. */ /** * Generate a cryptographically random code verifier (43-128 chars, base64url). */ export function generateCodeVerifier() { const array = new Uint8Array(48) // 48 bytes → 64-char base64url string crypto.getRandomValues(array) return base64urlEncode(array) } /** * Derive the code challenge from the verifier (S256 method). * @param {string} verifier * @returns {Promise} */ export async function generateCodeChallenge(verifier) { const encoder = new TextEncoder() const data = encoder.encode(verifier) const digest = await crypto.subtle.digest('SHA-256', data) return base64urlEncode(new Uint8Array(digest)) } /** * Generate a random state parameter to prevent CSRF. */ export function generateState() { const array = new Uint8Array(16) crypto.getRandomValues(array) return base64urlEncode(array) } // ── Internal helpers ────────────────────────────────────────────────────────── function base64urlEncode(buffer) { return btoa(String.fromCharCode(...buffer)) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, '') }