Files
sf-sim/packages/sim-shared/domain/JWT.ts

120 lines
2.9 KiB
TypeScript

import { sign } from "node:crypto"
export type JWTHeader = {
alg: string,
typ: string,
kid: string
}
export type JWTPayload<T> = {
/** (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<T> = {
header: JWTHeader,
payload?: JWTPayload<T>,
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<T> {
public rawToken: string
private decodedPayload: JWTPayload<T> | undefined
constructor(
token: string
) {
this.rawToken = token
this.decodedPayload = this.decodePayload()
}
public static fromParts<T>(args: {
header: JWTHeader,
payload?: JWTPayload<T>,
sigantureData?: {
privateKey: string,
algorythm: string
}
}) {
const strHeader = JSON.stringify(args.header)
const base64Header = Buffer.from(strHeader).toString("base64url")
let token = base64Header
if (args.payload != undefined) {
const strPayload = JSON.stringify(args.payload)
const base64payload = Buffer.from(strPayload).toString("base64url")
token += ("." + base64payload)
}
if (args.sigantureData != undefined) {
const base64signature = signJWT({
algorythm: args.sigantureData.algorythm,
privateKey: args.sigantureData.privateKey,
data: token
}).toString("base64url")
token += ("." + base64signature)
}
return token
}
private decodePayload(): JWTPayload<T> {
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
}
}