/* eslint-disable @typescript-eslint/no-explicit-any */ import { Elysia } from 'elysia' import jwt, { type JWTPayloadSpec } from '@elysiajs/jwt' import bearer from '@elysiajs/bearer' import { prisma } from '../lib/prisma' // ========================================================= // JWT Secret Validation // ========================================================= const secret = process.env.JWT_SECRET if (!secret) throw new Error('JWT_SECRET environment variable is missing') // ========================================================= // Auth Middleware Plugin // ========================================================= export default function apiAuth(app: Elysia) { if (!secret) throw new Error('JWT_SECRET environment variable is missing') return app // Register Bearer and JWT plugins .use(bearer()) // ✅ Extracts Bearer token automatically (case-insensitive) .use( jwt({ name: 'jwt', secret, }) ) // Derive user from JWT or cookie .derive(async ({ bearer, cookie, jwt }) => { // Normalize token type to string or undefined const token = (typeof bearer === 'string' ? bearer : undefined) ?? (typeof cookie?.token?.value === 'string' ? cookie.token.value : undefined) let user: Awaited> | null = null if (token) { try { const decoded = (await jwt.verify(token)) as JWTPayloadSpec if (decoded?.sub && typeof decoded.sub === 'string') { user = await prisma.user.findUnique({ where: { id: decoded.sub }, }) } } catch (err) { console.warn('[SERVER][apiAuth] Invalid token:', (err as Error).message) } } return { user } }) // Protect all routes by default .onBeforeHandle(({ user, set, request }) => { // Whitelist public routes if needed const publicPaths = ['/auth/login', '/auth/register', '/public'] if (publicPaths.some((path) => request.url.includes(path))) return if (!user) { set.status = 401 return { error: 'Unauthorized' } } }) }