import fp from 'fastify-plugin'; import jwt from '@fastify/jwt'; import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'; import type { AccessTokenPayload } from '../lib/jwt.js'; declare module 'fastify' { interface FastifyInstance { authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise; } } declare module '@fastify/jwt' { interface FastifyJWT { payload: AccessTokenPayload; user: AccessTokenPayload; } } export default fp(async (app: FastifyInstance) => { const jwtSecret = process.env.JWT_SECRET; const jwtRefreshSecret = process.env.JWT_REFRESH_SECRET; if (!jwtSecret || !jwtRefreshSecret) { throw new Error('JWT_SECRET and JWT_REFRESH_SECRET environment variables are required'); } // Access token JWT await app.register(jwt, { secret: jwtSecret, }); // Refresh token JWT (separate namespace) await app.register(jwt, { secret: jwtRefreshSecret, namespace: 'refresh', decoratorName: 'jwtRefresh', }); // Auth decorator app.decorate('authenticate', async (request: FastifyRequest, reply: FastifyReply) => { try { await request.jwtVerify(); } catch { reply.code(401).send({ error: 'Unauthorized', message: 'Invalid or expired token' }); } }); });