import logger from 'log' import {generateSecret, jwtVerify, type KeyLike, SignJWT} from 'jose' import {JWT_ALGORITHM} from './const' const log = logger('crypto:jwt') export type Key = KeyLike | Uint8Array export class JWTcontext { private constructor(private readonly key: Key) {} public static async gen_key(): Promise { log.trace('generate key') return await generateSecret(JWT_ALGORITHM()) } public static new(key: Key): JWTcontext { return new JWTcontext(key) } public static async new_random(): Promise { const k = await JWTcontext.gen_key() return new JWTcontext(k) } public async sign( message: T, set_issued: boolean = false, exp?: number | string | Date, audience?: string | string[], issuer?: string ): Promise { log.trace('sign JWT') log.trace('Config :', { set_issued, exp, issuer }) let jwt = new SignJWT({message}).setProtectedHeader({alg: JWT_ALGORITHM()}) if (set_issued) jwt = jwt.setIssuedAt() if (issuer !== undefined) jwt = jwt.setIssuer(issuer) if (audience !== undefined) jwt = jwt.setAudience(audience) if (exp !== undefined) jwt = jwt.setExpirationTime(exp) return await jwt.sign(this.key) } public async verify(jwt: string, audience?: string | string[], issuer?: string | string[]): Promise { log.debug('Verify JWT') log.trace('Issuer :', issuer) log.trace('Audience :', audience) try { let payload = await jwtVerify(jwt, this.key, {audience, issuer}) return payload.payload.message as T } catch (e) { log.warn('JWT verification failed') log.debug(`Error : ${e}`) } return null } }