import { FastifyPluginAsync, FastifyRequest } from 'fastify'; import fp from 'fastify-plugin'; import * as jose from 'jose'; import { config } from '../config.js'; declare module 'fastify' { interface FastifyRequest { userId: string; } } const secret = new TextEncoder().encode(config.jwt.secret); export async function signAccessToken(userId: string): Promise { return new jose.SignJWT({ sub: userId }) .setProtectedHeader({ alg: 'HS256' }) .setIssuer(config.jwt.issuer) .setIssuedAt() .setExpirationTime(`${config.jwt.accessTtl}s`) .sign(secret); } export async function verifyAccessToken(token: string): Promise { const { payload } = await jose.jwtVerify(token, secret, { issuer: config.jwt.issuer, }); if (!payload.sub) throw new Error('Invalid token: missing sub'); return payload.sub; } const authPlugin: FastifyPluginAsync = async (fastify) => { fastify.decorateRequest('userId', ''); }; export default fp(authPlugin, { name: 'auth' });