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.

164 lines 6.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createFirebaseTokenGenerator = exports.handleCryptoSignerError = exports.FirebaseTokenGenerator = exports.EmulatedSigner = exports.BLACKLISTED_CLAIMS = void 0; const crypto_signer_1 = require("./jwt/crypto-signer"); const utils_1 = require("./jwt/utils"); const validator_1 = require("./validator"); const error_1 = require("./error"); const firebase_1 = require("./firebase"); const ALGORITHM_NONE = "none"; const ONE_HOUR_IN_SECONDS = 60 * 60; exports.BLACKLISTED_CLAIMS = [ "acr", "amr", "at_hash", "aud", "auth_time", "azp", "cnf", "c_hash", "exp", "iat", "iss", "jti", "nbf", "nonce", ]; const FIREBASE_AUDIENCE = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"; class EmulatedSigner { constructor() { this.algorithm = ALGORITHM_NONE; } async sign(token) { return (0, utils_1.stringToBase64)(token); } getAccountId() { return Promise.resolve("firebase-auth-emulator@example.com"); } } exports.EmulatedSigner = EmulatedSigner; class FirebaseTokenGenerator { constructor(signer, tenantId) { this.tenantId = tenantId; if (!(0, validator_1.isNonNullObject)(signer)) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CREDENTIAL, "INTERNAL ASSERT: Must provide a CryptoSigner to use FirebaseTokenGenerator."); } if (typeof this.tenantId !== "undefined" && !(0, validator_1.isNonEmptyString)(this.tenantId)) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "`tenantId` argument must be a non-empty string."); } this.signer = signer; } createCustomToken(uid, developerClaims) { let errorMessage; if (!(0, validator_1.isNonEmptyString)(uid)) { errorMessage = "`uid` argument must be a non-empty string uid."; } else if (uid.length > 128) { errorMessage = "`uid` argument must a uid with less than or equal to 128 characters."; } else if (!FirebaseTokenGenerator.isDeveloperClaimsValid_(developerClaims)) { errorMessage = "`developerClaims` argument must be a valid, non-null object containing the developer claims."; } if (errorMessage) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, errorMessage); } const claims = {}; if (typeof developerClaims !== "undefined") { for (const key in developerClaims) { if (Object.prototype.hasOwnProperty.call(developerClaims, key)) { if (exports.BLACKLISTED_CLAIMS.indexOf(key) !== -1) { throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, `Developer claim "${key}" is reserved and cannot be specified.`); } claims[key] = developerClaims[key]; } } } return this.signer .getAccountId() .then(async (account) => { const header = { alg: this.signer.algorithm, typ: "JWT", }; const iat = Math.floor(Date.now() / 1000); const body = { aud: FIREBASE_AUDIENCE, iat, exp: iat + ONE_HOUR_IN_SECONDS, iss: account, sub: account, uid, }; if (this.tenantId) { body.tenant_id = this.tenantId; } if (Object.keys(claims).length > 0) { body.claims = claims; } const token = `${FirebaseTokenGenerator.encodeSegment(header)}.${FirebaseTokenGenerator.encodeSegment(body)}`; const signPromise = await this.signer.sign(token); return Promise.all([token, signPromise]); }) .then(([token, signature]) => { return `${token}.${signature}`; }) .catch((err) => { throw handleCryptoSignerError(err); }); } static encodeSegment(segment) { if (typeof segment === "object") { return (0, utils_1.objectToBase64)(segment); } return (0, utils_1.stringToBase64)(segment); } static isDeveloperClaimsValid_(developerClaims) { if (typeof developerClaims === "undefined") { return true; } return (0, validator_1.isNonNullObject)(developerClaims); } } exports.FirebaseTokenGenerator = FirebaseTokenGenerator; function handleCryptoSignerError(err) { var _a; if (!(err instanceof crypto_signer_1.CryptoSignerError)) { return err; } if (err.code === crypto_signer_1.CryptoSignerErrorCode.SERVER_ERROR && (0, validator_1.isNonNullObject)(err.cause)) { return new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, "Error returned from server: " + ((_a = err.cause) === null || _a === void 0 ? void 0 : _a.message) + ". Additionally, an " + "internal error occurred while attempting to extract the " + "errorcode from the error."); } return new error_1.FirebaseAuthError(mapToAuthClientErrorCode(err.code), err.message); } exports.handleCryptoSignerError = handleCryptoSignerError; function mapToAuthClientErrorCode(code) { switch (code) { case crypto_signer_1.CryptoSignerErrorCode.INVALID_CREDENTIAL: return error_1.AuthClientErrorCode.INVALID_CREDENTIAL; case crypto_signer_1.CryptoSignerErrorCode.INVALID_ARGUMENT: return error_1.AuthClientErrorCode.INVALID_ARGUMENT; default: return error_1.AuthClientErrorCode.INTERNAL_ERROR; } } function createFirebaseTokenGenerator(credential, tenantId) { try { const signer = (0, firebase_1.useEmulator)() ? new EmulatedSigner() : new crypto_signer_1.ServiceAccountSigner(credential); return new FirebaseTokenGenerator(signer, tenantId); } catch (err) { throw handleCryptoSignerError(err); } } exports.createFirebaseTokenGenerator = createFirebaseTokenGenerator; //# sourceMappingURL=token-generator.js.map