import { createError, getRequestHeader, type H3Event } from 'h3' import { getRouteRequirement } from '../utils/auth-rules' import { verifyAccessToken } from '../utils/jwt' /** * Lê o header Authorization e extrai o token Bearer. * * @param event Evento HTTP atual. * @returns Token JWT sem o prefixo `Bearer`. * @throws {H3Error} Quando o header estiver ausente ou em formato inválido. */ function extractBearerToken(event: H3Event): string { const authHeader = getRequestHeader(event, 'authorization') if (!authHeader) { throw createError({ statusCode: 401, statusMessage: 'Missing Authorization header' }) } const [scheme, token] = authHeader.split(' ') if (!scheme || !token || scheme.toLowerCase() !== 'bearer') { throw createError({ statusCode: 401, statusMessage: 'Authorization must be Bearer token' }) } return token.trim() } /** * Middleware global de autenticação. * Em rotas protegidas, valida o JWT e preenche `event.context.auth`. * * @param event Evento HTTP atual. * @throws {H3Error} Quando houver falha de autenticação. */ export default defineEventHandler(async (event) => { const routeRequirement = getRouteRequirement(event.method, event.path) if (!routeRequirement) { return } if (getRequestHeader(event, 'x-user-id')) { throw createError({ statusCode: 400, statusMessage: 'Custom identity headers are not allowed. Use JWT claims instead.' }) } const token = extractBearerToken(event) const payload = await verifyAccessToken(event, token) event.context.auth = { id: payload.sub, token } })