diff --git a/src/firebase.ts b/src/firebase.ts index f349fa4..406390f 100644 --- a/src/firebase.ts +++ b/src/firebase.ts @@ -2,32 +2,48 @@ import { AsyncMiddleware, Fallback } from './types' import { FIREBASE_COOKIE_KEY } from './constants' import { NextRequest } from 'next/server' import { handleFallback } from './handle-fallback' -import { decodeProtectedHeader, jwtVerify, JWK, importJWK } from 'jose' +import { decodeProtectedHeader, jwtVerify, importJWK } from 'jose' +import { toJwk } from 'js-x509-utils' -export const makeFirebaseInspector = (fallback: Fallback): AsyncMiddleware => { +export const makeFirebaseInspector = ( + fallback: Fallback, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + customHandler?: (payload: any) => boolean +): AsyncMiddleware => { return async (request, event) => { - const ok = await verifyFirebaseIdToken(request) + const ok = await verifyFirebaseIdToken(request, customHandler) if (ok) return return handleFallback(fallback, request, event) } } -const JWK_ENDPOINT = - 'https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com' - -const verifyFirebaseIdToken = async (req: NextRequest): Promise => { - const token = req.cookies[FIREBASE_COOKIE_KEY] +const verifyFirebaseIdToken = async ( + req: NextRequest, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + customHandler?: (payload: any) => boolean +): Promise => { + const cookieKey = + process.env.FORTRESS_FIREBASE_COOKIE_KEY ?? FIREBASE_COOKIE_KEY + const token = req.cookies[cookieKey] if (!token) return false - const { keys }: { keys: JWK[] } = await fetch(JWK_ENDPOINT).then((res) => - res.json() - ) + const endpoint = + process.env.FORTRESS_FIREBASE_MODE === 'session' + ? 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys' + : 'https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com' + + try { + const keys: Record = await fetch(endpoint).then((res) => + res.json() + ) - const { kid } = decodeProtectedHeader(token) - const jwk = keys.find((key) => key.kid === kid) - if (!jwk) return false + const { kid = '', alg } = decodeProtectedHeader(token) + const jwk = await toJwk(keys[kid], 'pem') - return jwtVerify(token, await importJWK(jwk)) - .then(() => true) - .catch(() => false) + return jwtVerify(token, await importJWK({ ...jwk, alg })) + .then((res) => customHandler?.(res.payload) ?? true) + .catch(() => false) + } catch (_) { + return false + } }