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.

124 lines 4.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getFirebaseAdminTokenProvider = exports.ServiceAccountCredential = void 0; const jwt_1 = require("./jwt"); const response_cache_1 = require("./response-cache"); const TOKEN_EXPIRY_THRESHOLD_MILLIS = 5 * 60 * 1000; const GOOGLE_TOKEN_AUDIENCE = "https://accounts.google.com/o/oauth2/token"; const GOOGLE_AUTH_TOKEN_HOST = "accounts.google.com"; const GOOGLE_AUTH_TOKEN_PATH = "/o/oauth2/token"; const ONE_HOUR_IN_SECONDS = 60 * 60; const JWT_ALGORITHM = "RS256"; class ServiceAccountCredential { constructor(serviceAccount) { this.projectId = serviceAccount.projectId; this.privateKey = serviceAccount.privateKey; this.clientEmail = serviceAccount.clientEmail; this.cache = (0, response_cache_1.getResponseCache)(); } async fetchAccessToken(url) { const token = await this.createJwt(); const postData = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3A" + "grant-type%3Ajwt-bearer&assertion=" + token; const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", Authorization: `Bearer ${token}`, Accept: "application/json", }, body: postData, }); const clone = response.clone(); const data = await response.json(); if (!data.access_token || !data.expires_in) { throw new Error(`Unexpected response while fetching access token: ${JSON.stringify(data)}`); } const body = JSON.stringify({ accessToken: data.access_token, expirationTime: Date.now() + data.expires_in * 1000, }); return new Response(body, clone); } async fetchAndCacheAccessToken(url) { const response = await this.fetchAccessToken(url); await this.cache.put(url, response.clone()); return response; } async getAccessToken(forceRefresh) { const url = new URL(`https://${GOOGLE_AUTH_TOKEN_HOST}${GOOGLE_AUTH_TOKEN_PATH}`); if (forceRefresh) { return requestAccessToken(await this.fetchAndCacheAccessToken(url)); } const cachedResponse = await this.cache.get(url); if (!cachedResponse) { return requestAccessToken(await this.fetchAndCacheAccessToken(url)); } const response = await requestAccessToken(cachedResponse); if (response.expirationTime - Date.now() <= TOKEN_EXPIRY_THRESHOLD_MILLIS) { return requestAccessToken(await this.fetchAndCacheAccessToken(url)); } return response; } async createJwt() { const iat = Math.floor(Date.now() / 1000); const payload = { aud: GOOGLE_TOKEN_AUDIENCE, iat, exp: iat + ONE_HOUR_IN_SECONDS, iss: this.clientEmail, sub: this.clientEmail, scope: [ "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/firebase.database", "https://www.googleapis.com/auth/firebase.messaging", "https://www.googleapis.com/auth/identitytoolkit", "https://www.googleapis.com/auth/userinfo.email", ].join(" "), }; return (0, jwt_1.sign)({ payload, privateKey: this.privateKey, algorithm: JWT_ALGORITHM, }); } } exports.ServiceAccountCredential = ServiceAccountCredential; async function requestAccessToken(res) { if (!res.ok) { const data = await res.json(); throw new Error(getErrorMessage(data)); } const data = await res.json(); if (!data.accessToken || !data.expirationTime) { throw new Error(`Unexpected response while fetching access token: ${JSON.stringify(data)}`); } return data; } function getErrorMessage(data) { const detail = getDetailFromResponse(data); return `Error fetching access token: ${detail}`; } function getDetailFromResponse(data) { if (data === null || data === void 0 ? void 0 : data.error) { const json = data; let detail = json.error; if (json.error_description) { detail += " (" + json.error_description + ")"; } return detail; } return "Missing error payload"; } const getFirebaseAdminTokenProvider = (account) => { const credential = new ServiceAccountCredential(account); async function getToken(forceRefresh = false) { return credential.getAccessToken(forceRefresh); } return { getToken, }; }; exports.getFirebaseAdminTokenProvider = getFirebaseAdminTokenProvider; //# sourceMappingURL=credential.js.map