58 lines
1.6 KiB
TypeScript
58 lines
1.6 KiB
TypeScript
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
|
|
}
|
|
})
|