UNPKG

hono

Version:

Web framework built on Web Standards

153 lines (152 loc) 5.38 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; 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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var jwt_exports = {}; __export(jwt_exports, { decode: () => decode, decodeHeader: () => decodeHeader, isTokenHeader: () => isTokenHeader, sign: () => sign, verify: () => verify, verifyFromJwks: () => verifyFromJwks }); module.exports = __toCommonJS(jwt_exports); var import_encode = require("../../utils/encode"); var import_jwa = require("./jwa"); var import_jws = require("./jws"); var import_types = require("./types"); var import_utf8 = require("./utf8"); const encodeJwtPart = (part) => (0, import_encode.encodeBase64Url)(import_utf8.utf8Encoder.encode(JSON.stringify(part)).buffer).replace(/=/g, ""); const encodeSignaturePart = (buf) => (0, import_encode.encodeBase64Url)(buf).replace(/=/g, ""); const decodeJwtPart = (part) => JSON.parse(import_utf8.utf8Decoder.decode((0, import_encode.decodeBase64Url)(part))); function isTokenHeader(obj) { if (typeof obj === "object" && obj !== null) { const objWithAlg = obj; return "alg" in objWithAlg && Object.values(import_jwa.AlgorithmTypes).includes(objWithAlg.alg) && (!("typ" in objWithAlg) || objWithAlg.typ === "JWT"); } return false; } const sign = async (payload, privateKey, alg = "HS256") => { const encodedPayload = encodeJwtPart(payload); let encodedHeader; if (typeof privateKey === "object" && "alg" in privateKey) { alg = privateKey.alg; encodedHeader = encodeJwtPart({ alg, typ: "JWT", kid: privateKey.kid }); } else { encodedHeader = encodeJwtPart({ alg, typ: "JWT" }); } const partialToken = `${encodedHeader}.${encodedPayload}`; const signaturePart = await (0, import_jws.signing)(privateKey, alg, import_utf8.utf8Encoder.encode(partialToken)); const signature = encodeSignaturePart(signaturePart); return `${partialToken}.${signature}`; }; const verify = async (token, publicKey, alg = "HS256") => { const tokenParts = token.split("."); if (tokenParts.length !== 3) { throw new import_types.JwtTokenInvalid(token); } const { header, payload } = decode(token); if (!isTokenHeader(header)) { throw new import_types.JwtHeaderInvalid(header); } const now = Date.now() / 1e3 | 0; if (payload.nbf && payload.nbf > now) { throw new import_types.JwtTokenNotBefore(token); } if (payload.exp && payload.exp <= now) { throw new import_types.JwtTokenExpired(token); } if (payload.iat && now < payload.iat) { throw new import_types.JwtTokenIssuedAt(now, payload.iat); } const headerPayload = token.substring(0, token.lastIndexOf(".")); const verified = await (0, import_jws.verifying)( publicKey, alg, (0, import_encode.decodeBase64Url)(tokenParts[2]), import_utf8.utf8Encoder.encode(headerPayload) ); if (!verified) { throw new import_types.JwtTokenSignatureMismatched(token); } return payload; }; const verifyFromJwks = async (token, options, init) => { const header = decodeHeader(token); if (!isTokenHeader(header)) { throw new import_types.JwtHeaderInvalid(header); } if (!header.kid) { throw new import_types.JwtHeaderRequiresKid(header); } if (options.jwks_uri) { const response = await fetch(options.jwks_uri, init); if (!response.ok) { throw new Error(`failed to fetch JWKS from ${options.jwks_uri}`); } const data = await response.json(); if (!data.keys) { throw new Error('invalid JWKS response. "keys" field is missing'); } if (!Array.isArray(data.keys)) { throw new Error('invalid JWKS response. "keys" field is not an array'); } if (options.keys) { options.keys.push(...data.keys); } else { options.keys = data.keys; } } else if (!options.keys) { throw new Error('verifyFromJwks requires options for either "keys" or "jwks_uri" or both'); } const matchingKey = options.keys.find((key) => key.kid === header.kid); if (!matchingKey) { throw new import_types.JwtTokenInvalid(token); } return await verify(token, matchingKey, matchingKey.alg || header.alg); }; const decode = (token) => { try { const [h, p] = token.split("."); const header = decodeJwtPart(h); const payload = decodeJwtPart(p); return { header, payload }; } catch { throw new import_types.JwtTokenInvalid(token); } }; const decodeHeader = (token) => { try { const [h] = token.split("."); return decodeJwtPart(h); } catch { throw new import_types.JwtTokenInvalid(token); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { decode, decodeHeader, isTokenHeader, sign, verify, verifyFromJwks });