import { FastifyPluginAsync, FastifyRequest } from "fastify"; import fastifyPlugin from "fastify-plugin"; import fastifyJwt from "@fastify/jwt"; import fastifyCookie from "@fastify/cookie"; import fastifyOauth2 from "@fastify/oauth2"; declare module "fastify" { interface FastifyInstance { authenticate: (request: FastifyRequest) => Promise; oauth2Discord: any; } } declare module "@fastify/jwt" { interface FastifyJWT { user: { id: string; username: string; email?: string; avatar?: string; isAdmin: boolean; }; } } const getJwtSecret = (): string => { const secret = process.env.JWT_SECRET; if (!secret) { throw new Error("JWT_SECRET environment variable is required"); } return secret; }; const authPlugin: FastifyPluginAsync = async (app) => { const jwtSecret = getJwtSecret(); // Register cookie plugin with signing secret app.register(fastifyCookie, { secret: jwtSecret, }); // Register JWT plugin app.register(fastifyJwt, { secret: jwtSecret, sign: { algorithm: "HS256", }, verify: { algorithms: ["HS256"], }, cookie: { cookieName: "auth-token", signed: true, }, formatUser: (payload: { sub: string; email?: string; username: string; isAdmin: boolean }) => { return { id: payload.sub, email: payload.email, username: payload.username, isAdmin: payload.isAdmin, }; }, }); // Register Discord OAuth2 app.register(fastifyOauth2, { name: "oauth2Discord", scope: ["identify", "email", "guilds", "guilds.members.read"], credentials: { client: { id: process.env.DISCORD_CLIENT_ID || "", secret: process.env.DISCORD_CLIENT_SECRET || "", }, auth: fastifyOauth2.DISCORD_CONFIGURATION, }, startRedirectPath: "/api/auth/login", callbackUri: `${process.env.BASE_URL || "http://localhost:3000"}/api/auth/callback`, }); // Authentication decorator app.decorate("authenticate", async (request: FastifyRequest) => { try { await request.jwtVerify(); } catch (err) { throw app.httpErrors.unauthorized("Invalid token"); } }); }; export default fastifyPlugin(authPlugin);