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
feat(auth): enforced MFA via the session-validation gate (ADR-0069 D3, P1) (#2390)
Completes the session gate (after password expiry #2388) by reusing its
authGate seam for enforced MFA.
- plugin-auth: computeAuthGate gains an MFA branch — when mfaRequired and the
user has no TOTP enrolled (sys_user.two_factor_enabled), block with
MFA_REQUIRED once the grace window (mfa_required_at + mfaGracePeriodDays)
elapses. mfa_required_at is stamped lazily on first required-but-unenrolled
session. isAuthGateActive() also trips on mfaRequired.
- bindAuthSettings: mfa_required + mfa_grace_period_days; enabling mfa_required
force-enables the twoFactor plugin so /two-factor/* enrollment exists.
- platform-objects: sys_user.mfa_required_at column.
- service-settings: Multi-factor settings group.
Default-off / additive; ADR-0049 (enforcement ships with the setting).
Verified live (dogfood): mfa_required + grace 7, un-enrolled user — within
grace NOT gated (mfa_required_at stamped); past grace -> 403 MFA_REQUIRED;
/two-factor/enable reachable (200, totpURI) while blocked; after enrollment the
gate lifts (native 2FA verification takes over); admin within grace NOT blocked.
Unit: plugin-auth 191 + service-settings 129 + platform-objects 63 + core 299 +
rest 140 green; full build (incl. strict DTS) green.
objectui follow-up: Console must render a TOTP-enroll prompt on 403
MFA_REQUIRED. Per-org require_mfa + dispatcher/MCP gate remain follow-ups (#2375).
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Completes the session-validation gate: when `mfa_required` (new `auth` setting) is on, an authenticated user without TOTP enrolled is blocked from protected resources with `403 MFA_REQUIRED` once their `mfa_grace_period_days` (default 7) window elapses — while the two-factor enrollment endpoints stay reachable so they can comply. Reuses the `authGate` seam shipped in #2388 (a second posture branch in `computeAuthGate`).
10
+
11
+
- New `auth` settings `mfa_required` (toggle) + `mfa_grace_period_days`; enabling `mfa_required` also force-enables the `twoFactor` plugin so `/two-factor/*` enrollment exists.
12
+
- New `sys_user.mfa_required_at` column — the grace clock, stamped lazily the first time a user is seen required-but-unenrolled.
13
+
-`isAuthGateActive()` now also trips on `mfa_required` (still zero-overhead when off).
14
+
15
+
Default-off / additive (no upgrade behavior change); per ADR-0049 the setting ships with its enforcement.
16
+
17
+
**Needs an objectui follow-up**: the Console should handle a `403 MFA_REQUIRED` by showing the TOTP-enrollment prompt. Per-org `sys_organization.require_mfa` and the dispatcher/MCP gate remain follow-ups (#2375).
Copy file name to clipboardExpand all lines: packages/services/service-settings/src/manifests/auth.manifest.ts
+28Lines changed: 28 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -180,6 +180,34 @@ const manifest = {
180
180
max: 3600,
181
181
description: 'Sliding window over which the request cap above is counted.',
182
182
},
183
+
{
184
+
type: 'group',
185
+
id: 'multi_factor',
186
+
label: 'Multi-factor',
187
+
required: false,
188
+
description: 'Require members to protect their account with an authenticator app (TOTP).',
189
+
},
190
+
{
191
+
type: 'toggle',
192
+
key: 'mfa_required',
193
+
label: 'Require multi-factor authentication',
194
+
required: false,
195
+
default: false,
196
+
description:
197
+
'Users without an authenticator enrolled are blocked from data once their grace period ends. Enabling this also turns on the two-factor feature so users can enroll.',
0 commit comments