import { sign } from "node:crypto" export type JWTHeader = { alg: string, typ: string, kid: string } export type JWTPayload = { /** (Issuer) Quién emitió el token */ iss?: string; /** (Subject) De quién trata el token (ej. user_id) */ sub?: string; /** (Audience) Destinatarios del token */ aud?: string | string[]; /** (Expiration Time) Fecha de expiración (Unix timestamp) */ exp?: number; /** (Not Before) No válido antes de esta fecha (Unix timestamp) */ nbf?: number; /** (Issued At) Cuándo fue emitido (Unix timestamp) */ iat?: number; /** (JWT ID) Identificador único para este token */ jti?: string; /** (Authentication Context Class) */ acr?: string } & T export type JWTSignature = { e?: string, ktv?: string, n?: string } export type JWT = { header: JWTHeader, payload?: JWTPayload, signature: JWTSignature } // todo pasar a la clase JWT function signJWT(args: { algorythm: "sha256" | string, data: string, privateKey: string }) { const signature = sign( args.algorythm, Buffer.from(args.data), args.privateKey ) return signature } export class JWTToken { public rawToken: string private decodedPayload: JWTPayload | undefined constructor( token: string ) { this.rawToken = token this.decodedPayload = this.decodePayload() } public static fromParts(args: { header: JWTHeader, payload?: JWTPayload, sigantureData?: { privateKey: string, algorythm: string } }) { const strHeader = JSON.stringify(args.header) const base64Header = Buffer.from(strHeader).toString("base64url") let msg = base64Header if (args.payload != undefined) { const strPayload = JSON.stringify(args.payload) const base64payload = Buffer.from(strPayload).toString("base64url") msg += ("." + base64payload) } if (args.sigantureData != undefined) { const base64signature = signJWT({ algorythm: args.sigantureData.algorythm, privateKey: args.sigantureData.privateKey, data: msg }).toString("base64url") msg += ("." + base64signature) } console.log("JWT", msg) } private decodePayload(): JWTPayload { if (this.rawToken == undefined) throw new Error("La clase no tiene un token definido") const rawTokenPayload = this.rawToken.split(".")[1] if (rawTokenPayload == undefined) throw new Error("El token no tiene payload") return JSON.parse(Buffer.from(rawTokenPayload, "base64").toString("utf8")); } public isExpired() { if (this.decodedPayload == undefined) throw new Error("Error leyendo el payload del token") const now = new Date() const expirationDate = this.decodedPayload.exp if (expirationDate == undefined) return false // un token sin fecha de expiracion no expira if (expirationDate * 1000 <= now.getTime()) return true return false } }