Pular para o conteúdo principal
Versão: main (dev) 🚧

ADR-003 — JWT Bearer config-driven authentication (no placeholder gate)

Date: 2026-05-08 Status: Superseded by ADR-006 (2026-06-11) — o JWT externo config-driven passou a ser opt-in (--auth external-jwt); o default virou Identity local + dual-scheme. O conteúdo abaixo permanece válido para o caminho opt-in.

Context

A Fase 2 shipou PlaceholderAuthenticationHandler (aceita qualquer request como autenticado) gated por #if !DEBUG + #error em Release. O gate impedia deploy acidental, mas tinha custos:

  • Template não buildava em Release out-of-the-box. Quem clonava + tentava CI logo via "build FAILED" — barulho desnecessário.
  • Cada consumidor reescrevia o wiring de auth do zero no primeiro deploy. Decisão repetida N vezes.
  • A escolha de scheme (JWT/Entra/Cookie) é raramente "uma decisão informada" — é "JWT Bearer por default na maioria dos casos, com IdP variando".

Decision

Substituir o placeholder por JWT Bearer config-driven:

  • appsettings:Authentication:Jwt:{Authority, Audience, RequireHttpsMetadata} é a config canônica.
  • JwtOptions bound com ValidateDataAnnotations().ValidateOnStart() — Authority e Audience são [Required].
  • Host falha cedo no app.Run() se config vazia, com mensagem clara apontando o campo faltante.
  • appsettings.json ship com Authority/Audience vazios; appsettings.Development.json (gitignored, copiado do .sample) traz valores plausíveis dev (https://localhost:5001, RequireHttpsMetadata: false).
  • Para schemes alternativos (Entra ID, Cookie), o consumidor substitui o AddJwtBearer(...) em Program.cs — DevPack devpack-docs/areas/Identity/README.md § Authentication scheme — production checklist cobre as variações.
  • Tests usam TestAuthenticationHandler do ITLab.Template.DevPack.Testing que override do scheme JWT no factory; JwtOptions recebe valores não-vazios via services.Configure<JwtOptions> na IntegrationTestFactory.ConfigureAdditionalServices para satisfazer ValidateOnStart em CI sem appsettings.Development.json.

Consequences

Positivas:

  • Template builda Debug + Release out-of-the-box.
  • Consumidor só configura dados (Authority/Audience via env vars / Key Vault), não código.
  • Validação cedo: typo em config = erro na startup, não 401 silencioso em runtime.

Negativas:

  • Quem realmente quer um scheme diferente (Cookie/Entra Web App) precisa editar Program.cs — mas isso é inevitável em qualquer scheme.
  • appsettings.Development.json.sample precisa ser copiado para .json antes de dotnet run local funcionar (mitigado: README cobre no passo 3 do "Primeiro run").

Alternatives considered

OpçãoPor que descartada
Manter PlaceholderAuthenticationHandler com gateCusto perpétuo no consumidor; gate trava CI.
Microsoft Entra ID como defaultDemais opinionado para clientes Azure — exclui não-Azure.
Cookie auth como defaultNão combina com APIs REST/SPA, que é o caso comum do template.
Validar config só no OnAuthenticationFailedFalha tarde (no primeiro request) em vez de cedo (na startup).

References

  • CLAUDE.md § Authentication.
  • src/.../Api/Authentication/JwtOptions.cs.
  • Commit de7e821 original (depois reescrito como 30f1c72).