You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Completes enforced MFA with the two remaining tails.
- platform-objects: sys_organization.require_mfa (per-org tightening above the
global floor).
- plugin-auth: computeAuthGate treats the active org's require_mfa as an
effective MFA requirement even when global mfaRequired is off; isAuthGateActive
consults a 60s-TTL cached "any org requires MFA" flag (lazy background refresh)
so the cheap sync check stays honest without per-request org queries.
- runtime: enforceAuthGate runs in the dispatcher after resolveExecutionContext,
gating MCP/GraphQL/embedded data paths the same way the REST seam gates the
Console — reusing the shared core evaluateAuthGate + allow-list.
Default-off / additive; ADR-0049.
Verified live (dogfood): with GLOBAL mfa off, an org member whose org has
require_mfa=true is gated 403 MFA_REQUIRED while an admin with no org is not
(per-org scoping). With global mfa on, POST /api/v1/mcp returns 403 with
details.code=MFA_REQUIRED (the dispatcher seam). Unit: plugin-auth 195 +
runtime 444 + core 299 + platform-objects 63 + service-settings 129 green;
full build incl. strict DTS green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auth: per-org MFA + dispatcher/MCP gate — complete the ADR-0069 enforced-MFA story
8
+
9
+
Two follow-ups that make enforced MFA total:
10
+
11
+
-**Per-org `sys_organization.require_mfa`** — an org may require MFA above the global floor. `computeAuthGate` now treats the active org's `require_mfa` as an effective MFA requirement even when the global `mfa_required` is off; `isAuthGateActive()` stays cheap via a 60s-TTL "any org requires MFA" cache (lazy background refresh), so a brand-new per-org requirement activates the gate on the next request without per-request org queries.
12
+
-**Dispatcher/MCP gate** — the auth-policy gate now also runs in the runtime dispatcher (after `resolveExecutionContext`), so MCP / GraphQL / embedded data paths enforce `PASSWORD_EXPIRED` / `MFA_REQUIRED` consistently with the REST seam (reusing the shared `evaluateAuthGate` allow-list). Previously only the REST surface (the Console) was gated.
13
+
14
+
Default-off / additive. Per ADR-0049 each setting ships with its enforcement.
0 commit comments