/** * src/oauth/supabase-jwt.ts — Issue real Supabase JWTs for OAuth code exchange. * * Strategy: * 1. After the consent page stores an authorization code (with user_id) in * Supabase, the token endpoint consumes that code and retrieves user_id. * 2. This module verifies the user exists via the Admin API, then signs an * HS256 JWT using SUPABASE_JWT_SECRET — the same secret Supabase GoTrue * uses internally. * 3. The resulting JWT starts with "eyJ" → extractAuth classifies it as a * JWT → the Go sidecar validates it via ValidateSupabaseJWT (HS256 path). * * Why HS256 self-sign instead of GoTrue session APIs: * - Zero extra HTTP round-trips beyond the user-existence check. * - The Go sidecar uses loadLiveBillingMetadata to fetch tier from the DB, * so JWT-embedded app_metadata.billing_tier isn't required. * - generate_link + OTP exchange adds fragile indirection for no benefit. * * Fallback: If env vars aren't set (test/dev), returns null and the token * endpoint falls back to placeholder tokens. * * Required env vars: * - SUPABASE_URL (e.g. https://xxxx.supabase.co) * - SUPABASE_SERVICE_ROLE_KEY (for Admin API user lookup) * - SUPABASE_JWT_SECRET (for HS256 signing) */ export interface SupabaseSessionTokens { access_token: string; refresh_token: string; expires_in: number; token_type: "bearer"; } /** * Verify the user exists in Supabase, then self-sign an HS256 JWT using * SUPABASE_JWT_SECRET. Returns null if any required env var is missing * or the user doesn't exist. */ export declare function issueSupabaseJWT(userId: string): Promise; export declare function refreshSupabaseSession(refreshToken: string): Promise;