Files
nuxt-frontend/server/utils/auth-config.ts
2026-04-14 19:44:21 -05:00

94 lines
2.9 KiB
TypeScript

import { createError, type H3Event } from 'h3'
export interface AuthRuntimeConfig {
issuer: string
audience: string
accessTtlSec: number
refreshTtlSec: number
privateKeyPem: string
publicKeyPem: string
kid: string
refreshTokenPepper: string
}
/**
* Converte uma string para inteiro positivo e valida o resultado.
*
* @param value Valor recebido do runtime config.
* @param label Nome amigável do campo para mensagens de erro.
* @returns Número inteiro positivo.
* @throws {H3Error} Quando o valor não for um inteiro positivo.
*/
function parsePositiveInt(value: string, label: string): number {
const parsed = Number.parseInt(value, 10)
if (!Number.isFinite(parsed) || parsed <= 0) {
throw createError({
statusCode: 500,
statusMessage: `${label} must be a positive integer`
})
}
return parsed
}
/**
* Normaliza uma chave PEM salva em variável de ambiente.
* Troca `\\n` por quebra de linha real e remove espaços nas pontas.
*
* @param rawValue Valor bruto vindo do ambiente.
* @param label Nome amigável do campo para mensagens de erro.
* @returns Chave PEM pronta para uso.
* @throws {H3Error} Quando a chave estiver vazia.
*/
function normalizePem(rawValue: string, label: string): string {
const normalized = rawValue.replace(/\\n/g, '\n').trim()
if (!normalized) {
throw createError({
statusCode: 500,
statusMessage: `${label} is required`
})
}
return normalized
}
/**
* Lê e valida todas as configurações obrigatórias de autenticação.
*
* @param event Evento da requisição (opcional), usado para acessar runtime config.
* @returns Objeto com configurações de JWT e refresh token já validadas.
* @throws {H3Error} Quando algum campo obrigatório estiver ausente ou inválido.
*/
export function getAuthRuntimeConfig(event?: H3Event): AuthRuntimeConfig {
const runtimeConfig = useRuntimeConfig(event)
const issuer = String(runtimeConfig.jwtIssuer ?? '').trim()
const audience = String(runtimeConfig.jwtAudience ?? '').trim()
const kid = String(runtimeConfig.jwtKid ?? '').trim()
if (!issuer) {
throw createError({ statusCode: 500, statusMessage: 'JWT issuer is required' })
}
if (!audience) {
throw createError({ statusCode: 500, statusMessage: 'JWT audience is required' })
}
if (!kid) {
throw createError({ statusCode: 500, statusMessage: 'JWT kid is required' })
}
return {
issuer,
audience,
kid,
accessTtlSec: parsePositiveInt(String(runtimeConfig.jwtAccessTtlSec), 'JWT access TTL'),
refreshTtlSec: parsePositiveInt(String(runtimeConfig.jwtRefreshTtlSec), 'JWT refresh TTL'),
privateKeyPem: normalizePem(String(runtimeConfig.jwtPrivateKeyPem ?? ''), 'JWT private key'),
publicKeyPem: normalizePem(String(runtimeConfig.jwtPublicKeyPem ?? ''), 'JWT public key'),
refreshTokenPepper: String(runtimeConfig.refreshTokenPepper ?? '')
}
}