UNPKG

@pedwise/next-firebase-auth-edge

Version:

Next.js 13 Firebase Authentication for Edge and server runtimes. Dedicated for Next 13 server components. Compatible with Next.js middleware.

109 lines 4.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.verify = exports.getPublicCryptoKey = void 0; const error_1 = require("./error"); const decode_1 = require("./decode"); const utils_1 = require("./utils"); const consts_1 = require("./consts"); const pem_to_public_key_1 = require("../pem-to-public-key"); const firebase_1 = require("../firebase"); const keyMap = {}; async function getCachedPublicKeyFromCertificate(pem) { if (keyMap[pem]) { return keyMap[pem]; } return (keyMap[pem] = await (0, pem_to_public_key_1.pemToPublicKey)(pem)); } function createKeyFromCertificatePEM(pem) { return getCachedPublicKeyFromCertificate(pem); } async function getPublicCryptoKey(publicKey, options) { if (publicKey.startsWith("-----BEGIN CERTIFICATE-----")) { return createKeyFromCertificatePEM(publicKey .replace("-----BEGIN CERTIFICATE-----", "") .replace("-----END CERTIFICATE-----", "") .replace(/\n/g, "")); } const base64 = publicKey .replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replace(/\n/g, ""); const buffer = (0, utils_1.base64StringToArrayBuffer)(base64); return crypto.subtle.importKey(options.format, buffer, consts_1.ALGORITHMS.RS256, false, ["verify"]); } exports.getPublicCryptoKey = getPublicCryptoKey; async function verify(jwtString, secretOrPublicKey, options = { format: "spki", algorithm: "RS256", }) { if (options.nonce !== undefined && !options.nonce.trim()) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "nonce must be a non-empty string"); } const clockTimestamp = options.clockTimestamp || Math.floor(Date.now() / 1000); if (!jwtString) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "jwt must be valid"); } const parts = jwtString.split("."); if (parts.length !== 3) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "jwt malformed"); } const decodedToken = (0, decode_1.decode)(jwtString, { complete: true }); if (!decodedToken) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "invalid token"); } const header = decodedToken.header; const signature = parts[2].trim(); const hasSignature = signature !== ""; if (!(0, firebase_1.useEmulator)() && !hasSignature && secretOrPublicKey) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_SIGNATURE, "jwt signature is required"); } if (!(0, firebase_1.useEmulator)() && hasSignature && !secretOrPublicKey) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_CREDENTIAL, "secret or public key must be provided"); } if (!(0, firebase_1.useEmulator)() && decodedToken.header.alg !== options.algorithm) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "unsupported algorithm: " + decodedToken.header.alg); } if (!(0, firebase_1.useEmulator)()) { const data = parts.slice(0, 2).join("."); const key = await getPublicCryptoKey(secretOrPublicKey, options); const jwtBuffer = (0, utils_1.stringToArrayBuffer)(data); const sigBuffer = (0, utils_1.base64StringToArrayBuffer)(signature); const result = await crypto.subtle.verify(consts_1.ALGORITHMS[options.algorithm], key, sigBuffer, jwtBuffer); if (!result) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_SIGNATURE, "invalid signature"); } } const payload = decodedToken.payload; if (typeof payload.nbf !== "undefined") { if (typeof payload.nbf !== "number") { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "invalid nbf value"); } if (payload.nbf > clockTimestamp) { throw new error_1.JwtError(error_1.JwtErrorCode.TOKEN_EXPIRED, "jwt not active: " + new Date(payload.nbf * 1000).toISOString()); } } if (typeof payload.exp !== "undefined") { if (typeof payload.exp !== "number") { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "invalid exp value"); } if (clockTimestamp >= payload.exp) { throw new error_1.JwtError(error_1.JwtErrorCode.TOKEN_EXPIRED, "token expired: " + new Date(payload.exp * 1000).toISOString()); } } if (options.nonce) { if (payload.nonce !== options.nonce) { throw new error_1.JwtError(error_1.JwtErrorCode.INVALID_ARGUMENT, "jwt nonce invalid. expected: " + options.nonce); } } if (options.complete === true) { const signature = decodedToken.signature; return { header: header, payload: payload, signature: signature, }; } return payload; } exports.verify = verify; //# sourceMappingURL=verify.js.map