0018 — Auth das views no micronaut-security nativo¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-06-17 · Decidido em: 2026-06-17
Contexto¶
O gate de login das views era um AuthFilter (@Filter("/**")) caseiro, rodando
em paralelo ao SecurityFilter do micronaut-security — reimplementando
autenticação, autorização por path e tradução de rejeição que o framework já dá.
A API (/api/**, Bearer estático — decisão 0011) já
era nativa. Manter dois mundos de auth aumentava a superfície e divergia do
framework.
Decisão¶
Substituir o AuthFilter por primitivos nativos (passo 1 — mantendo o
Firebase client-side, o SessionTokenService e o CsrfTokens desta vez):
SessionAuthenticationFetcher(AuthenticationFetcher) lê o cookiexadm_session, valida viaSessionTokenServicee devolveAuthentication.ViewSecurityRule(SecurityRule) replica o tri-estado enabled / bypass (dev/test) / fail-closed (prod) das views.ViewRejectionHandler(ExceptionHandler<AuthorizationException>— o security 5.x removeu oRejectionHandler) faz 302 browser / 401 JSON / 503 fail-closed, preservando o comportamento do filtro antigo.AuthSupportguarda constantes/helpers que sobreviveram; o fetcher mantém os atributos de request, entãoGlobalViewModeleCsrfTokensficam intactos.
Escolha entre rotas (Regra nº 1): preferida a migração por peças nativas
(mantém Firebase) em vez do full OIDC (Google como provider redirect-based). O
OIDC trocaria o mecanismo de login — justamente o que nenhum teste exercita
hoje — mudaria UX e exigiria client-secret/redirect URI no Google Console.
"Sem quebrar nada" pesou pela rota incremental.
Consequências¶
- A autenticação passa a fluir pelo framework (
Authentication,@Secured,SecurityRule) — fim do filtro paralelo (~217 linhas). - Paridade provada: o
AuthIntegrationTest(302/401/403, callback, logout, jornada, Bearer) passou sem alterar asserções. É a rede que protege os próximos passos. - Sessão (JWT,
SessionTokenService) e CSRF (CsrfTokens) permanecem caseiros por decisão — a migração deles paramicronaut-security-jwt/-csrffoi avaliada e descartada: a config nativa é sempre-ligada e exige segredo HS256 válido no startup, enquanto a auth deste app é condicional (segredo vazio em dev/test bypass e em prod mal-configurado). Conciliar isso preservando o fail-closed exigiria mudar a semântica (segredo random-por-boot ou fail-fast no startup) — risco de segurança que não compensa ~150 linhas. O caseiro é limpo, testado e já fica atrás do fetcher nativo (o ganho estrutural veio no passo 1). O CSRF nativo seria multi-aba seguro (stateless HMAC), mas esbarra na mesma impedância do segredo.
Alternativas consideradas¶
- Full OIDC (micronaut-security-oauth2): maior redução de código, mas alto risco e mudança de UX/infra; o caminho novo não tem teste. Descartado por ora.
- Manter o
AuthFilter: contraria o objetivo de usar o framework e mantém a divergência com a auth da API. Descartado.