UNPKG

@treasure-dev/auth

Version:

Authentication token utilities for the Treasure ecosystem

142 lines (136 loc) 4.91 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { createAuth: () => createAuth }); module.exports = __toCommonJS(src_exports); // src/auth.ts var import_client_kms = require("@aws-sdk/client-kms"); var import_jsonwebtoken = __toESM(require("jsonwebtoken")); // src/base64.ts var base64 = (value) => Buffer.from(value).toString("base64"); var base64url = (value) => base64(value).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); // src/kms.ts var publicKeyCache = {}; var kmsSign = async (kms, key, message) => { const result = await kms.sign({ Message: Buffer.from(message), KeyId: key, SigningAlgorithm: "RSASSA_PKCS1_V1_5_SHA_256", MessageType: "RAW" }); if (!result.Signature) { throw new Error("Unable to generate signature"); } return base64url(result.Signature); }; var kmsGetPublicKey = async (kms, key, cacheTtlSeconds = 3600) => { if (!publicKeyCache[key] || Date.now() - publicKeyCache[key].lastUpdatedAt > cacheTtlSeconds * 1e3) { const result = await kms.getPublicKey({ KeyId: key }); if (!result.PublicKey) { throw new Error("Unable to fetch public key"); } publicKeyCache[key] = { publicKey: `-----BEGIN PUBLIC KEY----- ${base64(result.PublicKey)} -----END PUBLIC KEY-----`, lastUpdatedAt: Date.now() }; } return publicKeyCache[key].publicKey; }; // src/auth.ts var JWT_HEADER = base64url( JSON.stringify({ alg: "RS256", typ: "JWT" }) ); var createAuth = ({ kmsKey, kmsClientConfig, kmsPublicKeyCacheTtlSeconds = 3600, // 1 hour issuer, audience, expirationTimeSeconds = 86400 // 1 day }) => { const kms = kmsClientConfig ? new import_client_kms.KMS(kmsClientConfig) : new import_client_kms.KMS(); return { generateJWT: async (subject, overrides) => { const payload = { iss: overrides?.issuer ?? issuer ?? "treasure.lol", aud: overrides?.audience ?? audience ?? "treasure.lol", sub: subject, iat: Math.floor((overrides?.issuedAt ?? /* @__PURE__ */ new Date()).getTime() / 1e3), exp: Math.floor( overrides?.expiresAt ? overrides.expiresAt.getTime() / 1e3 : (/* @__PURE__ */ new Date()).getTime() / 1e3 + expirationTimeSeconds ), ctx: overrides?.context ?? {} }; const message = `${JWT_HEADER}.${base64url(JSON.stringify(payload))}`; const signature = await kmsSign(kms, kmsKey, message); return `${message}.${signature}`; }, verifyJWT: async (token) => { const decoded = import_jsonwebtoken.default.decode(token); const now = Math.floor(Date.now() / 1e3); if (!decoded.exp || decoded.exp < now) { throw new Error( `Token expired at ${decoded.exp}, current time is ${now}` ); } if (audience && decoded.aud.toLowerCase() !== audience.toLowerCase()) { throw new Error( `Expected audience "${audience}", but found "${decoded.aud}"` ); } if (issuer && decoded.iss.toLowerCase() !== issuer.toLowerCase()) { throw new Error( `Expected issuer "${issuer}", but found "${decoded.iss}"` ); } const publicKey = await kmsGetPublicKey( kms, kmsKey, kmsPublicKeyCacheTtlSeconds ); return import_jsonwebtoken.default.verify(token, publicKey, { algorithms: ["RS256"] }); } }; }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createAuth });