UNPKG

hono

Version:

Web framework built on Web Standards

82 lines (81 loc) 2.58 kB
// src/utils/jwt/jwt.ts import { decodeBase64Url, encodeBase64Url } from "../../utils/encode.js"; import { AlgorithmTypes } from "./jwa.js"; import { signing, verifying } from "./jws.js"; import { JwtHeaderInvalid, JwtTokenExpired, JwtTokenInvalid, JwtTokenIssuedAt, JwtTokenNotBefore, JwtTokenSignatureMismatched } from "./types.js"; import { utf8Decoder, utf8Encoder } from "./utf8.js"; var encodeJwtPart = (part) => encodeBase64Url(utf8Encoder.encode(JSON.stringify(part))).replace(/=/g, ""); var encodeSignaturePart = (buf) => encodeBase64Url(buf).replace(/=/g, ""); var decodeJwtPart = (part) => JSON.parse(utf8Decoder.decode(decodeBase64Url(part))); function isTokenHeader(obj) { if (typeof obj === "object" && obj !== null) { const objWithAlg = obj; return "alg" in objWithAlg && Object.values(AlgorithmTypes).includes(objWithAlg.alg) && (!("typ" in objWithAlg) || objWithAlg.typ === "JWT"); } return false; } var sign = async (payload, privateKey, alg = "HS256") => { const encodedPayload = encodeJwtPart(payload); const encodedHeader = encodeJwtPart({ alg, typ: "JWT" }); const partialToken = `${encodedHeader}.${encodedPayload}`; const signaturePart = await signing(privateKey, alg, utf8Encoder.encode(partialToken)); const signature = encodeSignaturePart(signaturePart); return `${partialToken}.${signature}`; }; var verify = async (token, publicKey, alg = "HS256") => { const tokenParts = token.split("."); if (tokenParts.length !== 3) { throw new JwtTokenInvalid(token); } const { header, payload } = decode(token); if (!isTokenHeader(header)) { throw new JwtHeaderInvalid(header); } const now = Math.floor(Date.now() / 1e3); if (payload.nbf && payload.nbf > now) { throw new JwtTokenNotBefore(token); } if (payload.exp && payload.exp <= now) { throw new JwtTokenExpired(token); } if (payload.iat && now < payload.iat) { throw new JwtTokenIssuedAt(now, payload.iat); } const headerPayload = token.substring(0, token.lastIndexOf(".")); const verified = await verifying( publicKey, alg, decodeBase64Url(tokenParts[2]), utf8Encoder.encode(headerPayload) ); if (!verified) { throw new JwtTokenSignatureMismatched(token); } return payload; }; var decode = (token) => { try { const [h, p] = token.split("."); const header = decodeJwtPart(h); const payload = decodeJwtPart(p); return { header, payload }; } catch (e) { throw new JwtTokenInvalid(token); } }; export { decode, isTokenHeader, sign, verify };