Skip to content

Instantly share code, notes, and snippets.

@sannajammeh
Created June 24, 2023 23:44
Show Gist options
  • Save sannajammeh/c74ab369f0a02dc29ed6abf36ce95bc6 to your computer and use it in GitHub Desktop.
Save sannajammeh/c74ab369f0a02dc29ed6abf36ce95bc6 to your computer and use it in GitHub Desktop.
Edge id token validator
import type { DecodedIdToken } from 'firebase-admin/lib/auth/token-verifier';
import * as jose from 'jose';
type JWKS = Record<string, string>;
interface JWTHeader {
kid: string;
alg: 'RS256';
typ: 'JWT';
}
export const verifyIdToken = async (
idToken: string
): Promise<DecodedIdToken> => {
if (!idToken) throw new Error('auth_no_token');
// Fetch public keys from google identity toolkit
const snapshot = await fetch(
'https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com'
);
if (!snapshot.ok) {
throw new Error('google_jwks_unavailable');
}
// Decode the public keys
const jwks: JWKS = await snapshot.json();
// Get token header
const header: JWTHeader = JSON.parse(
Buffer.from(idToken.split('.')[0], 'base64').toString('ascii')
);
// Validate header
validateHeader(header);
validatePayload(
JSON.parse(
Buffer.from(idToken.split('.')[1], 'base64').toString('ascii')
) as jose.JWTPayload
);
const { payload, protectedHeader } = await jose.jwtVerify(
idToken,
await jose.importX509(jwks[header.kid], 'RS256'),
{
issuer: 'https://securetoken.google.com/<ISSUER>',
audience: '<AUD>',
}
);
return payload as unknown as DecodedIdToken;
};
const validateHeader = (header: JWTHeader): boolean => {
if (header.alg !== 'RS256') {
throw new Error(`auth_invalid_signature`);
}
if (header.typ !== 'JWT') {
throw new Error(`auth_invalid_token`);
}
return true;
};
const validatePayload = (body: jose.JWTPayload): boolean => {
if (body.aud !== `${process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID}`) {
throw new Error(`auth_invalid_token`);
}
return true;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment