feat(auth): per-instance opt-out for the email_verified strict check #115
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol#115
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Carol's OIDC flow requires
payload.email_verified === true(after the userinfo fallback from #105) before accepting a sign-in. The check is the documented defence against the account-takeover-via-unverified-email vector enumerated in ADR-0015 §3 (inherited by ADR-0017 §3 threat #13).For a self-hoster with complete control over their IdP's user population — Authentik administering a small internal team, OIDC tenant where the only path to user creation is admin-driven — the verified-email check is friction without security benefit. Every user that exists in the IdP exists because an operator put them there; "is this email verified?" reduces to "did the admin verify it?", which they already know.
There's no acceptable way to make this opt-out without making the trade-off explicit. The ticket is intentionally about how to make the opt-out hard to misuse, not just how to add a flag.
Scope
OIDC_<NAME>_REQUIRE_EMAIL_VERIFIED. Defaulttrue(current behaviour). Accepted opt-out value: literal stringfalseonly — anything else (including empty string, "no", "0", "off") falls back totrue. Anti-typo defence.parseConfigs→InstanceConfig→buildInstance→extractProfileinlib/auth/oidc-providers.ts.extractProfile's final check, when the flag isfalse:emailto be present (Carol's linking decision tree needs it — see ADR-0015's no-auto-merge-by-email refusal paths, which still apply regardless of this flag).emailVerified === truecheck.emailVerified(still call it ifemailitself is missing from id_token).[oidc:<name>] email_verified check is DISABLEDat instance-resolution time (not per-request — once per process, on startup-style discovery). Self-hosters reading container logs should see this without having to grep.tests/auth/oidc-providers.test.ts: env-parsing test that the flag round-trips on instance config.tests/api/oauth.test.ts: end-to-end scenario — id_token withemail_verified: falseAND env opt-out → session created. Same id_token without the env opt-out (existing test) →oidc_claimredirect. Tests must cover both directions.docs/oidc-self-hoster-guide.md: new sub-section under "Troubleshooting" or as a sibling — labelled clearly as a foot-gun. Lead with the threat model, then the env var. Example:Out of scope
email_verifiedof"true"(string) or1(number) to satisfy the strict check. That's a different change with a different threat model. The strict check is intentionally=== true.emailclaim itself.Acceptance
OIDC_AUTHENTIK_REQUIRE_EMAIL_VERIFIED=false, restarts the container, and observes a single[oidc:authentik] email_verified check is DISABLEDline in the startup-adjacent logs.email_verified: falsein the id_token signs in successfully against that instance.true(default) still gets?error=oidc_claim.docs/adr/.