Repository navigation
Conversation
In plugin mode every AuthKit sign-in asks Mfa\Policy before it sets a
session. A user with a factor answers a code; a user who must use MFA and
has none enrolls an authenticator on the spot; a profile that can't
satisfy the user's MFA refuses with 403 workos_mfa_blocked.
- Mfa\PendingLogin parks the WorkOS response server-side; the browser
only holds an mfa_token (profile-bound, single use, 5 wrong codes,
10 minutes, filter workos_mfa_pending_ttl)
- POST /auth/mfa/enroll; /challenge and /verify accept mfa_token and
only the sign-in's own factors and challenges
- WorkOS's mfa_enrollment now enrolls in the same step
- LoginCompleter::finish() is the shared last step
- hosted-AuthKit sign-ins finish on /workos/login/{profile}/?workos_mfa=
- Mfa\PasswordGuard: password-only sign-ins refuse users with MFA
(application passwords exempt; workos_mfa_allow_password_fallback)
- React shell: MfaEnroll step (QR + setup key), MfaChallenge takes
mfa_token, resume from data-mfa
bordoni
force-pushed
the
feat/mfa-plugin-enforcement
branch
from
October 18, 2026 17:24
d862ddd to
5fb5e4e
Compare
bordoni
marked this pull request as ready for review
October 19, 2026 05:28
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The plugin's MFA policy now runs at sign-in, so "Require" means something. Stacked on #86. Part of #28.
Changes
403 workos_mfa_blocked(filterworkos_mfa_block_message, actionworkos_mfa_blocked).Mfa\PendingLogin; the browser holds only anmfa_token. The token is bound to the Login Profile, single use, capped at 5 wrong codes, and expires after 10 minutes (filterworkos_mfa_pending_ttl).POST /auth/mfa/enroll./auth/mfa/challengeand/auth/mfa/verifyacceptmfa_token. With it, they only accept factors and challenges that belong to this sign-in.mfa_enrollmentnow enrolls in the same step instead of being refused.enforce: alwaysasks a user without a factor to enroll instead of refusing them./workos/login/{profile}/?workos_mfa=…. That page renders only the MFA step, even for redirect-mode profiles.?fallback=1,wp_signon(), headless mode, the login button) refuse users who have or need MFA. Application passwords are exempt. Filterworkos_mfa_allow_password_fallback.MfaEnrollstep,MfaChallengesendsmfa_token, and the shell can resume fromdata-mfa.Screenshots
Verified
MfaPluginEnforcementTest(14 tests), run through the real REST routes with WorkOS mocked at the HTTP layer:always,mfa_enrollment) now pin both modes.main.tscandbun run buildpass.