Background
Across firebase_admin_sdk and downstream consumers like firebase_functions (which depends on firebase_admin_sdk), there are multiple overlapping implementations of JWT signature verification, JWKS / X.509 certificate fetching, and public key caching.
Currently, firebase_admin_sdk maintains both UrlKeyFetcher (for X.509 PEM certs) and JwksFetcher (for JSON Web Key Sets) in lib/src/utils/jwt.dart.
Current Inconsistencies & Duplication
- Inconsistent Key Caching & TTLs:
UrlKeyFetcher parses HTTP Cache-Control: max-age headers via string splitting and tracks expiration via DateTime.
JwksFetcher ignores HTTP Cache-Control headers entirely, hardcoding a static 6-hour TTL (6 * 60 * 60 * 1000) and tracking expiration via epoch integer comparison.
- Meanwhile, downstream in
firebase_functions, AuthBlockingTokenVerifier hand-rolled a third key fetcher (_getGoogleKeys()) that parses Cache-Control: max-age via regex and defaults to a 1-hour TTL.
- Inconsistent Clock Skew and Claim Validation:
- Neither
FirebaseTokenVerifier nor AppCheckTokenVerifier supports clock-skew tolerance on timestamps (iat, exp). However, Auth Blocking events in firebase_functions require a 5-minute clock skew on iat.
- Audience (
aud) claim handling varies: ID token verification assumes String, App Check assumes List, and downstream functions must handle both String and List polymorphically.
- Lack of Reusability for Downstream Packages:
- Because
PublicKeySignatureVerifier and JwksFetcher are either marked @internal or lack configuration ergonomics (v3 JWKS endpoints, clock skew, polymorphic audience matching), firebase_functions was forced to duplicate the entire JWT verification stack from scratch.
Proposed Action Items
Background
Across
firebase_admin_sdkand downstream consumers likefirebase_functions(which depends onfirebase_admin_sdk), there are multiple overlapping implementations of JWT signature verification, JWKS / X.509 certificate fetching, and public key caching.Currently,
firebase_admin_sdkmaintains bothUrlKeyFetcher(for X.509 PEM certs) andJwksFetcher(for JSON Web Key Sets) inlib/src/utils/jwt.dart.Current Inconsistencies & Duplication
UrlKeyFetcherparses HTTPCache-Control: max-ageheaders via string splitting and tracks expiration viaDateTime.JwksFetcherignores HTTPCache-Controlheaders entirely, hardcoding a static 6-hour TTL (6 * 60 * 60 * 1000) and tracking expiration via epoch integer comparison.firebase_functions,AuthBlockingTokenVerifierhand-rolled a third key fetcher (_getGoogleKeys()) that parsesCache-Control: max-agevia regex and defaults to a 1-hour TTL.FirebaseTokenVerifiernorAppCheckTokenVerifiersupports clock-skew tolerance on timestamps (iat,exp). However, Auth Blocking events infirebase_functionsrequire a 5-minute clock skew oniat.aud) claim handling varies: ID token verification assumesString, App Check assumesList, and downstream functions must handle bothStringandListpolymorphically.PublicKeySignatureVerifierandJwksFetcherare either marked@internalor lack configuration ergonomics (v3 JWKS endpoints, clock skew, polymorphic audience matching),firebase_functionswas forced to duplicate the entire JWT verification stack from scratch.Proposed Action Items
JwksFetcherandUrlKeyFetcherto share standard HTTPCache-Control: max-ageparsing (with a sensible default fallback like 1 hour).Duration clockSkewparameter) inPublicKeySignatureVerifierand claim validation.aud) matching (Stringvs.List<String>).google_cloud_server_auth) so downstream SDKs likefirebase_functionscan delete their custom verifiers and rely directly onfirebase_admin_sdk.