firebase-auth-cloudflare-workers
Version:
Zero-dependencies firebase auth library for Cloudflare Workers.
82 lines (81 loc) • 3.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmulatorSignatureVerifier = exports.PublicKeySignatureVerifier = exports.rs256alg = void 0;
const errors_1 = require("./errors");
const jwk_fetcher_1 = require("./jwk-fetcher");
const validator_1 = require("./validator");
// https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library
// https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams
exports.rs256alg = {
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: 'SHA-256',
};
/**
* Class for verifying JWT signature with a public key.
*/
class PublicKeySignatureVerifier {
keyFetcher;
constructor(keyFetcher) {
this.keyFetcher = keyFetcher;
if (!(0, validator_1.isNonNullObject)(keyFetcher)) {
throw new Error('The provided key fetcher is not an object or null.');
}
}
static withCertificateUrl(clientCertUrl, keyStorer) {
const fetcher = new jwk_fetcher_1.HTTPFetcher(clientCertUrl);
return new PublicKeySignatureVerifier(new jwk_fetcher_1.UrlKeyFetcher(fetcher, keyStorer));
}
/**
* Verifies the signature of a JWT using the provided secret or a function to fetch
* the public key.
*
* @param token - The JWT to be verified.
* @throws If the JWT is not a valid RS256 token.
* @returns A Promise resolving for a token with a valid signature.
*/
async verify(token) {
const { header } = token.decodedToken;
const publicKeys = await this.fetchPublicKeys();
for (const publicKey of publicKeys) {
if (publicKey.kid !== header.kid) {
continue;
}
const verified = await this.verifySignature(token, publicKey);
if (verified) {
// succeeded
return;
}
throw new errors_1.JwtError(errors_1.JwtErrorCode.INVALID_SIGNATURE, 'The token signature is invalid.');
}
throw new errors_1.JwtError(errors_1.JwtErrorCode.NO_MATCHING_KID, 'The token does not match the kid.');
}
async verifySignature(token, publicJWK) {
try {
const key = await crypto.subtle.importKey('jwk', publicJWK, exports.rs256alg, false, ['verify']);
return await crypto.subtle.verify(exports.rs256alg, key, token.decodedToken.signature, token.getHeaderPayloadBytes());
}
catch (err) {
throw new errors_1.JwtError(errors_1.JwtErrorCode.INVALID_SIGNATURE, `Error verifying signature: ${err}`);
}
}
async fetchPublicKeys() {
try {
return await this.keyFetcher.fetchPublicKeys();
}
catch (err) {
throw new errors_1.JwtError(errors_1.JwtErrorCode.KEY_FETCH_ERROR, `Error fetching public keys for Google certs: ${err}`);
}
}
}
exports.PublicKeySignatureVerifier = PublicKeySignatureVerifier;
/**
* Class for verifying unsigned (emulator) JWTs.
*/
class EmulatorSignatureVerifier {
async verify() {
// Signature checks skipped for emulator; no need to fetch public keys.
}
}
exports.EmulatorSignatureVerifier = EmulatorSignatureVerifier;