UNPKG

firebase-auth-cloudflare-workers

Version:

Zero-dependencies firebase auth library for Cloudflare Workers.

77 lines (76 loc) 2.91 kB
import { JwtError, JwtErrorCode } from './errors'; import { HTTPFetcher, UrlKeyFetcher } from './jwk-fetcher'; import { isNonNullObject } from './validator'; // https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library // https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams export const rs256alg = { name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: 'SHA-256', }; /** * Class for verifying JWT signature with a public key. */ export class PublicKeySignatureVerifier { keyFetcher; constructor(keyFetcher) { this.keyFetcher = keyFetcher; if (!isNonNullObject(keyFetcher)) { throw new Error('The provided key fetcher is not an object or null.'); } } static withCertificateUrl(clientCertUrl, keyStorer) { const fetcher = new HTTPFetcher(clientCertUrl); return new PublicKeySignatureVerifier(new UrlKeyFetcher(fetcher, keyStorer)); } /** * Verifies the signature of a JWT using the provided secret or a function to fetch * the public key. * * @param token - The JWT to be verified. * @throws If the JWT is not a valid RS256 token. * @returns A Promise resolving for a token with a valid signature. */ async verify(token) { const { header } = token.decodedToken; const publicKeys = await this.fetchPublicKeys(); for (const publicKey of publicKeys) { if (publicKey.kid !== header.kid) { continue; } const verified = await this.verifySignature(token, publicKey); if (verified) { // succeeded return; } throw new JwtError(JwtErrorCode.INVALID_SIGNATURE, 'The token signature is invalid.'); } throw new JwtError(JwtErrorCode.NO_MATCHING_KID, 'The token does not match the kid.'); } async verifySignature(token, publicJWK) { try { const key = await crypto.subtle.importKey('jwk', publicJWK, rs256alg, false, ['verify']); return await crypto.subtle.verify(rs256alg, key, token.decodedToken.signature, token.getHeaderPayloadBytes()); } catch (err) { throw new JwtError(JwtErrorCode.INVALID_SIGNATURE, `Error verifying signature: ${err}`); } } async fetchPublicKeys() { try { return await this.keyFetcher.fetchPublicKeys(); } catch (err) { throw new JwtError(JwtErrorCode.KEY_FETCH_ERROR, `Error fetching public keys for Google certs: ${err}`); } } } /** * Class for verifying unsigned (emulator) JWTs. */ export class EmulatorSignatureVerifier { async verify() { // Signature checks skipped for emulator; no need to fetch public keys. } }