UNPKG

firebase-edge-auth

Version:

Firebase token decoder for edge runtimes

79 lines (67 loc) 1.86 kB
import { jwtVerify, importX509, JWTPayload, JWSHeaderParameters } from "jose"; const FIREBASE_PUBLIC_KEYS_URL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"; let publicKeys: Record<string, string> = {}; let lastFetchTime = 0; export async function fetchPublicKeys(): Promise<void> { const response = await fetch(FIREBASE_PUBLIC_KEYS_URL); if (!response.ok) { throw new Error("Failed to fetch Firebase public keys"); } publicKeys = await response.json(); lastFetchTime = Date.now(); } async function getPublicKey(kid: string): Promise<CryptoKey> { if ( Date.now() - lastFetchTime > 3600000 || Object.keys(publicKeys).length === 0 ) { await fetchPublicKeys(); } if (!(kid in publicKeys)) { throw new Error("Public key not found"); } return await importX509(publicKeys[kid], "RS256"); } interface FirebaseIdentities { [key: string]: string[]; } interface FirebaseInfo { identities: FirebaseIdentities; sign_in_provider: string; } interface FirebasePayload extends JWTPayload { iss: string; aud: string; auth_time: number; user_id: string; sub: string; iat: number; exp: number; email: string; email_verified: boolean; firebase: FirebaseInfo; } export async function decodeFirebaseToken( token: string, projectId: string ): Promise<FirebasePayload> { try { const { payload } = await jwtVerify( token, async (header: JWSHeaderParameters) => { if (!header.kid) { throw new Error("No 'kid' claim in token header"); } return getPublicKey(header.kid); }, { audience: projectId, issuer: `https://securetoken.google.com/${projectId}`, } ); return payload as FirebasePayload; } catch (error) { throw new Error("Invalid Firebase token"); } }