import { createRemoteJWKSet, jwtVerify } from 'jose'; import { supabase, findOneGpi } from '../config/supabase.js'; import { IAppUser } from './authMiddleware.js'; const LOGTO_URL = process.env.LOGTO_URL || 'https://logto-admin-bzlued1boxl3t8ewsyn99an9.187.77.227.172.sslip.io'; const APP_ID = process.env.LOGTO_APP_ID || 'gpi-app-final'; const jwks = createRemoteJWKSet(new URL(`${LOGTO_URL}/oidc/jwks`)); export type AppUser = IAppUser; export async function authenticateRequest(req: any): Promise { const authHeader = req.headers.authorization; if (!authHeader?.startsWith('Bearer ')) { return null; } const token = authHeader.substring(7); try { const { payload } = await jwtVerify(token, jwks, { issuer: `${LOGTO_URL}/oidc`, audience: APP_ID }); const logtoId = payload.sub as string; // Primeiro tenta pelo Logto ID let user = await findOneGpi('users', { logto_id: logtoId }); // Se não encontrar, tenta pelo email (se houver no payload do token) if (!user && payload.email) { const email = payload.email as string; user = await findOneGpi('users', { email }); if (user) { // Vincula o Logto ID ao usuário existente await supabase .from('users') .update({ logto_id: logtoId }) .eq('id', user.id); user.logto_id = logtoId; console.log(`[Auth] Usuário ${email} vinculado ao Logto ID ${logtoId}`); } } // Auto-registro se não encontrar if (!user) { console.log(`[Auth] Usuário Logto ${logtoId} sem registro no GPI. Criando...`); const email = (payload.email as string) || ''; const name = (payload.name as string) || (payload.username as string) || email.split('@')[0]; const { data: newUser, error: createError } = await supabase .from('users') .insert({ email, name, logto_id: logtoId, role: 'user' }) .select() .single(); if (createError) { console.error('[Auth] Erro ao auto-registrar usuário:', createError); return null; } user = newUser; console.log(`[Auth] Novo usuário auto-registrado: ${email}`); } return { id: user.id || user._id, logtoId: user.logto_id, email: user.email, name: user.name, role: user.role }; } catch (error) { console.error('[Auth] Erro ao verificar token:', error); return null; } } export function requireAuth() { return async (req: any, res: any, next: any) => { const user = await authenticateRequest(req); if (!user) { return res.status(401).json({ error: 'Unauthorized' }); } req.appUser = user; next(); }; } export function requireRole(roles: string[]) { return async (req: any, res: any, next: any) => { const user = await authenticateRequest(req); if (!user) { return res.status(401).json({ error: 'Unauthorized' }); } if (!roles.includes(user.role)) { return res.status(403).json({ error: 'Forbidden' }); } req.appUser = user; next(); }; }