Spaces:
Paused
Paused
| import { nanoid } from "nanoid"; | |
| import { createHmac } from "crypto"; | |
| import { env } from "../config.js"; | |
| const toBase64URL = (b) => Buffer.from(b).toString("base64url"); | |
| const fromBase64URL = (b) => Buffer.from(b, "base64url").toString(); | |
| const makeHmac = (header, payload) => | |
| createHmac("sha256", env.jwtSecret) | |
| .update(`${header}.${payload}`) | |
| .digest("base64url"); | |
| const generate = () => { | |
| const exp = Math.floor(new Date().getTime() / 1000) + env.jwtLifetime; | |
| const header = toBase64URL(JSON.stringify({ | |
| alg: "HS256", | |
| typ: "JWT" | |
| })); | |
| const payload = toBase64URL(JSON.stringify({ | |
| jti: nanoid(8), | |
| exp, | |
| })); | |
| const signature = makeHmac(header, payload); | |
| return { | |
| token: `${header}.${payload}.${signature}`, | |
| exp: env.jwtLifetime - 2, | |
| }; | |
| } | |
| const verify = (jwt) => { | |
| const [header, payload, signature] = jwt.split(".", 3); | |
| const timestamp = Math.floor(new Date().getTime() / 1000); | |
| if ([header, payload, signature].join('.') !== jwt) { | |
| return false; | |
| } | |
| const verifySignature = makeHmac(header, payload); | |
| if (verifySignature !== signature) { | |
| return false; | |
| } | |
| if (timestamp >= JSON.parse(fromBase64URL(payload)).exp) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| export default { | |
| generate, | |
| verify, | |
| } | |