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.JwtOptionsbound comValidateDataAnnotations().ValidateOnStart()— Authority e Audience são[Required].- Host falha cedo no
app.Run()se config vazia, com mensagem clara apontando o campo faltante. appsettings.jsonship 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(...)emProgram.cs— DevPackdevpack-docs/areas/Identity/README.md§ Authentication scheme — production checklist cobre as variações. - Tests usam
TestAuthenticationHandlerdoITLab.Template.DevPack.Testingque override do scheme JWT no factory;JwtOptionsrecebe valores não-vazios viaservices.Configure<JwtOptions>naIntegrationTestFactory.ConfigureAdditionalServicespara satisfazerValidateOnStartem CI semappsettings.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.sampleprecisa ser copiado para.jsonantes dedotnet runlocal funcionar (mitigado: README cobre no passo 3 do "Primeiro run").
Alternatives considered
| Opção | Por que descartada |
|---|---|
Manter PlaceholderAuthenticationHandler com gate | Custo perpétuo no consumidor; gate trava CI. |
| Microsoft Entra ID como default | Demais opinionado para clientes Azure — exclui não-Azure. |
| Cookie auth como default | Não combina com APIs REST/SPA, que é o caso comum do template. |
Validar config só no OnAuthenticationFailed | Falha tarde (no primeiro request) em vez de cedo (na startup). |
References
CLAUDE.md§ Authentication.src/.../Api/Authentication/JwtOptions.cs.- Commit
de7e821original (depois reescrito como30f1c72).