April 5, 2023 Using jose to validate a Firebase JWT token We're working on adding support for Firebase auth to Zuplo (as we did with
Supabase) and in doing so came across their JWT signing approach which is one of
the more unusual. They sign their tokens with certs and they publish these certs
at a well-known URL:
https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com .
It took us a while to work out how to validate these JWT tokens using our
preferred library: Jose .
Hopefully this will save you some time if you're trying to do the same thing.
Note that we cache the certs in memory since they do not change often
(hopefully!).
let publicKeys : any ;
const getPublicKeys = async () => {
if (publicKeys) {
return publicKeys;
}
const res = await fetch (
`https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com` ,
);
publicKeys = await res. json ();
return publicKeys;
};
// This goes
// inside your auth function or middleware
const authHeader = request.headers. get ( "authorization" );
const token = authHeader. substring ( "bearer " . length );
const firebaseProjectId = "your-project-id" ;
const verifyFirebaseJwt = async ( firebaseJwt ) => {
const publicKeys = await getPublicKeys ();
const decodedToken = await jwtVerify (
firebaseJwt,
async ( header , _alg ) => {
const x509Cert = publicKeys[header.kid];
const publicKey = await importX509 (x509Cert, "RS256" );
return publicKey;
},
{
issuer: `https://securetoken.google.com/${ firebaseProjectId }` ,
audience: firebaseProjectId,
algorithms: [ "RS256" ],
},
);
return decodedToken.payload;
};
try {
// This will throw an error if the token is invalid
const tokenData = await verifyFirebaseJwt (token);
console. log ( `We got a valid token` , tokenData);
} catch (err) {
console. error ( `Invalid Token` , err);
}
Hope you find that useful. Of course, you could always sign up for a free Zuplo
account at portal.zuplo.com
and get Firebase JWT auth as easy as configuring a policy 👏 👏 👏