Skip to content

fix(utils): replace jwks-rsa with Web Crypto JWKS parsing - #3311

Open
lahirumaramba wants to merge 2 commits into
mainfrom
lm-jwks-webcrypto
Open

lahirumaramba wants to merge 2 commits into
mainfrom
lm-jwks-webcrypto

Conversation

@lahirumaramba

Copy link
Copy Markdown
Member

Fixes #3181

In v14.0.0, upgrading jwks-rsa to v4 introduced a synchronous CommonJS require('jose') call against jose v6, which only ships ES modules. On Node <22.12.0, and on serverless platforms like Vercel that start Node 22 and Node 24 with --no-experimental-require-module by default, importing firebase-admin/app-check, firebase-admin/phone-number-verification, or even firebase-admin/auth crashes immediately on startup with ERR_REQUIRE_ESM.

This PR removes jwks-rsa completely and fetches/converts JWKS public signing keys directly using our existing HttpClient and standard Web Crypto (globalThis.crypto.subtle). That preserves the 6-hour key cache and AppOptions.httpAgent support, eliminates the CJS/ESM boundary failure across all Node 22+ and serverless runtimes, and drops jwks-rsa, jose, and their transitive runtime dependencies.

Technical Details
  • JwksFetcher in src/utils/jwt.ts fetches the JWKS JSON payload via HttpClient (forwarding httpAgent identically to UrlKeyFetcher) and converts public signing JWKs into SPKI PEM strings via crypto.subtle.importKey('jwk', ...) and crypto.subtle.exportKey('spki', ...).
  • Supports RSA (RS256, RS384, RS512, PS256, PS384, PS512) and EC (P-256, P-384, P-521) signing keys.
  • Validates base64url key parameters (n/e and x/y) and skips non-signing (use !== 'sig') or private JWKs (d, p, q, dp, dq, qi, oth) prior to import so malformed JWKs cannot produce degenerate public keys.
  • Verified unit tests across jwt, app-check, auth, and phone-number-verification, as well as loading under node --no-experimental-require-module and Node v22.0.0 in both CommonJS and ESM.

In v14.0.0, upgrading `jwks-rsa` to v4 introduced a synchronous
`require('jose')` call against ESM-only `jose` v6. In Node `<22.12.0`
and on serverless runtimes like Vercel that disable `require(esm)` by
default, importing `firebase-admin/app-check`, `firebase-admin/auth`,
or `firebase-admin/phone-number-verification` crashes at startup with
`ERR_REQUIRE_ESM`.

Replace `jwks-rsa` in `JwksFetcher` with our existing `HttpClient` and
standard `crypto.subtle` JWK-to-SPKI conversion for RSA and EC signing
keys, and remove `jwks-rsa` from `package.json`.

Fixes #3181
@lahirumaramba
lahirumaramba requested a review from a team November 10, 2026 20:10

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request removes the jwks-rsa dependency and replaces it with a custom implementation for fetching and parsing JSON Web Key Sets (JWKS) using the Web Crypto API in src/utils/jwt.ts. It also updates the corresponding unit tests to cover the new logic. The review feedback suggests two key improvements: first, using Node.js's native Buffer to convert the public key SPKI to base64 more efficiently and idiomatically; second, adding a safety check to ensure resp.data is a non-null object before accessing its properties to prevent a potential runtime crash.

Comment thread src/utils/jwt.ts Resolved
Comment thread src/utils/jwt.ts Resolved
@lahirumaramba lahirumaramba added the release:stage Stage a release candidate label Nov 10, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:stage Stage a release candidate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Firebase v14] App Check verifyToken crashes with ERR_REQUIRE_ESM (jwks-rsa@4 require()s ESM-only jose@6)

1 participant