firebase / firebase/firebase-admin-node
[Firebase v14] App Check verifyToken crashes with ERR_REQUIRE_ESM (jwks-rsa@4 require()s ESM-only jose@6)
- Dominant language
- TypeScript
- Stars
- 1.7k
- Forks
- 419
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 16
Description
## Summary
`getAppCheck().verifyToken()` throws `ERR_REQUIRE_ESM` in a CommonJS/serverless runtime. The transitive dep `jwks-rsa@4.0.1` does `const jose = require('jose')` but declares `jose@^6.1.3`, and jose@6 is ESM-only, so the `require()` is a hard Node error.
## Error
```
Error [ERR_REQUIRE_ESM]: require() of ES Module
node_modules/.pnpm/jose@6.2.3/node_modules/jose/dist/webapi/index.js
from node_modules/.pnpm/jwks-rsa@4.0.1/node_modules/jwks-rsa/src/utils.js
not supported.
```
## Root cause (verified)
1. `firebase-admin@14.0.0` App Check verification depends on `jwks-rsa@4.0.1`.
2. `jwks-rsa@4.0.1` declares `"jose": "^6.1.3"` and loads it via CommonJS in `src/utils.js`:
```js
const jose = require('jose');
```
3. `jose@6.2.3` is ESM-only (`"type": "module"`, no `require` export condition).
4. Node refuses `require()` of an ESM module, so any path reaching App Check JWKS verification crashes.
`jwks-rsa@4.0.1` is internally inconsistent: a CommonJS `require('jose')` paired with a `jose` range whose only satisfying versions are ESM-only. `firebase-admin` ships this combination. It only uses `jose.importJWK` and `jose.exportSPKI`, which are API-identical across jose 4/5/6.
## Why production only
Dev uses an ESM-capable loader, so the import resolves via interop. In a production CommonJS/serverless bundle (`firebase-admin` is externalized and loaded with `require()`), the `require()`-of-ESM hits the hard error.
## Environment
- firebase-admin: 14.0.0
- jwks-rsa: 4.0.1 (transitive)
- jose resolved: 6.2.3 (ESM-only)
- Node.js 20+, CommonJS context, serverless (Vercel), Next.js 16, pnpm 11
## Expected
App Check verification works in a CommonJS/serverless runtime without manual dependency overrides.
## Suggested fix
Move `jwks-rsa` to a version that loads `jose` via dynamic `import()`, or constrain `jose` to a dual CJS/ESM build (`^4`/`^5`), or pin/patch `jwks-rsa`'s `jose` in `firebase-admin`.
## Workaround (consumer side)
```yaml
# pnpm-workspace.yaml
overrides:
jwks-rsa>jose: "4.15.9"
```
Contributor guide
Assessment
This issue has not been assessed yet.