feat(nextjs): add firebase-cookie-middleware with security hardening#739
feat(nextjs): add firebase-cookie-middleware with security hardening#739tyler-reitz wants to merge 10 commits into
Conversation
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
|
/gemini review |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
- Move jose from devDependencies to dependencies (runtime dep) - Strip API key from refresh error log (log origin+pathname only) - Fix exp=0 falsy guard (use !== undefined) - Release JWKS eviction lock on fetch error (add cacheDelete + try/finally) - Return 400 for malformed finalTarget URL instead of throwing TypeError - Fill in empty error message in composeMiddleware config guard - Align tenantId docs to string-only (function form deferred) - Add del() to CacheProvider interface and MemoryCacheProvider - Annotate @firebase/util and _AuthEmulatorRefreshToken as internal/fragile - Remove self-referential PR comment and resolved TODO - Centralize createToken test helper in middleware_test_utils.ts
Introduces the firebase-cookie-middleware package (v0.0.1) for Next.js 14/15/16, taking over from PR FirebaseExtended#640 (James Daniels). Security fixes applied during takeover review: - Emulator explicit opt-in only (env var not auto-detected) - JWT signature failure sets refreshable=false to prevent bypass - Verify refreshed token before accepting it - SSRF: loopback validation on emulator host - CSRF: Origin check on POST/DELETE to /__cookies__ - CHIPS: SameSite=None on partitioned cookies - JWKS eviction lock released in finally block - Falsy-zero TTL: require ttlSeconds > 0 before caching - Proxy targets validated; return 400 instead of throwing - Optional chaining on JWT payload access - Removed duplex: 'half' workaround (unnecessary in Node.js) Next.js 16: adds proxy export (proxy.ts replaces middleware.ts in Next.js 16 projects). proxy.ts runs on Node.js runtime only; middleware.ts remains available for Edge Runtime (deprecated). Also fixes pre-existing TypeScript strict-mode errors surfaced by upgrading moduleResolution from node to bundler. Ref: FirebaseExtended#640 Original work by: James Daniels ([email protected])
40b253c to
37050fa
Compare
|
/gemini review |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
The nextjs package is a self-contained sub-package with its own tsconfig and test runner. Including it in the root tsc/vitest runs causes failures because next is not installed as a root dependency.
Use **/ prefix so the patterns match at any directory depth, covering both src/nextjs/ and package/src/nextjs/ (the CI test job unpacks the npm tarball alongside the checkout, creating both paths). Also broaden node_modules exclusion to catch nested directories like functions/node_modules/.
|
/gemini review |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
|
/gemini review |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
…e throw with logout Three uncaught exceptions that crash middleware with 500: - proxy path: response.json() fired before response.ok check, returns 502 on non-JSON - refresh path: refreshResponse.json() now catches non-JSON bodies and calls logout() - refresh path: missing id_token now calls logout() instead of throwing Also remove duplicate JSDoc paragraph and fix two em-dashes in comments.
Local code review (in lieu of Gemini bot)The Gemini review bot has failed on every attempt for this PR (5+ runs). The diff is 2,500+ lines of all-new code, which appears to exceed the bot's input limit. I ran a local multi-angle review as a substitute. Three findings were fixed in the latest commit (bb006e9); the rest are documented below for your consideration. Fixed in bb006e91. Proxy path: 2. Refresh path: 3. Refresh path: Remaining findings (for your review)Security:
Operational correctness:
Minor correctness:
Forward compatibility:
Overall the package is solid. The three crash-on-error cases are fixed; the remaining items are defense-in-depth or edge-case correctness issues appropriate for follow-up issues. |
Summary
This PR introduces
firebase-cookie-middleware(v0.0.1), a production-ready Next.js middleware package for Firebase Auth cookie persistence. It takes over from #640 (original work by James Daniels, @jamesdaniels), which is being closed in favor of this PR to establish clear ownership.All logic from #640 has been carried forward. The following security issues were identified and addressed during the takeover review:
FIREBASE_AUTH_EMULATOR_HOSTis no longer auto-detected; requiresemulator: truein config to prevent unsigned token acceptance if the env var leaks into productionrefreshable=falseon signature failure: prevents refresh attempts when the original token has an invalid signature (not just expiry)localhost,127.0.0.1,::1)Originheader checked onPOST/DELETEto/__cookies__; cross-origin requests rejected with 403SameSite=Noneapplied correctly on partitioned cookies (was incorrectlySameSite=Laxin production)finallyblock to prevent deadlock on verification errorttlSeconds > 0required before caching;0no longer treated as "cache forever"400instead of an uncaught throwduplex: 'half': workaround was unnecessary and caused Node.js type errorsNext.js 16 compatibility: adds a
proxynamed export forproxy.ts(Node.js runtime). Themiddlewareexport remains formiddleware.tsusers (Edge Runtime, v14/15 and v16 deprecated path). Logic is identical between the two exports.Also fixes pre-existing TypeScript strict-mode errors surfaced by upgrading
moduleResolutionfromnodetobundler.Test plan
npm testinsrc/nextjs/)tsc --noEmitclean at repo root and insrc/nextjs/emulator: true+FIREBASE_AUTH_EMULATOR_HOSTsetproxy.tsexport in a Next.js 16 appAttribution
Original implementation by James Daniels ([email protected]), PR #640. Takeover and security hardening by Tyler Dixon.
Closes #640