Skip to content

✨ Add a ForceTwoFactor facade to bypass the 2FA enforcement - #1

Merged
mikaelpopowicz merged 1 commit into
mainfrom
feature/force-two-factor-bypass
Sep 23, 2026
Merged

mikaelpopowicz merged 1 commit into
mainfrom
feature/force-two-factor-bypass

Conversation

@mikaelpopowicz

Copy link
Copy Markdown
Collaborator

What

Adds a runtime bypass hook so specific requests can be exempted from the forced two-factor enrolment — the motivating case being SSO admins whose second factor is handled by the identity provider and who shouldn't be pushed into local (Fortify) 2FA. Mirrors the PasswordRotation::bypass() hook in laravel-password-rotation.

API

use BBSLab\NovaForceTwoFactor\Facades\ForceTwoFactor;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\Request;

ForceTwoFactor::bypass(
    fn (Request $request, Authenticatable $user) => $request->session()->get('sso') === true,
);

EnsureTwoFactorEnabled::shouldPassThrough() consults the callback only for an authenticated, not-yet-enrolled admin; returning true lets the request through. Several callbacks may be registered — any true exempts the request.

Design

  • New TwoFactorManager, bound as a container singleton in packageRegistered() (before the auto-registration guard), so the facade and the middleware share one instance and callbacks survive config:cache.
  • New ForceTwoFactor facade. No dependency on the password-rotation core (distinct 2FA semantics).
  • Backward compatible: with no callback registered, behaviour is unchanged.

Also

  • Commit composer.lock (and stop ignoring it) for reproducible CI — matching the base and nova twin.

Workbench demo

An is_sso column, a seeded SSO admin, and a ForceTwoFactor::bypass() callback in NovaServiceProvider. Under composer serve, sso@example.com reaches Nova without enrolling while no2fa-valid@example.com is still forced to.

Verification

  • Pint ✅ · PHPStan ✅ (larastan 3.12) · Pest 41 tests, 100% coverage ✅ · composer build seeds cleanly.

Register a callback (e.g. for SSO admins whose second factor is handled by the
identity provider) that exempts a request from the forced 2FA enrolment. Backed
by a container-singleton manager so callbacks survive config:cache and stay
test-isolated; the middleware consults it before redirecting an un-enrolled
admin to the User Security page.

The workbench demoes it: an `is_sso` column, a seeded SSO admin, and a
ForceTwoFactor::bypass() callback in NovaServiceProvider — under `composer
serve`, sso@example.com reaches Nova without enrolling while
no2fa-valid@example.com is still forced to.

Also commit composer.lock (and stop ignoring it) for reproducible CI, matching
laravel-password-rotation and nova-password-rotation.
Copilot AI lite review requested due to automatic review settings September 23, 2026 21:37
@mikaelpopowicz
mikaelpopowicz merged commit 25fde77 into main Sep 23, 2026
9 checks passed
@mikaelpopowicz
mikaelpopowicz deleted the feature/force-two-factor-bypass branch September 23, 2026 21:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Add feature coverage for multiple callback composition and short-circuit evaluation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds a ForceTwoFactor facade and singleton manager for runtime 2FA bypass callbacks, including an SSO workbench demonstration.

Changes:

  • Adds callback registration and middleware integration.
  • Adds SSO demo data, migration, and provider configuration.
  • Tracks composer.lock and updates .gitignore.

Review note: Add coverage for multiple callbacks, including false-then-true evaluation and short-circuiting.

File Description
workbench/​database/​seeders/​DatabaseSeeder.php Seeds an SSO admin.
workbench/​database/​migrations/​2024_01_01_000002_add_is_sso_to_users_table.php Adds the SSO database field.
workbench/​app/​Providers/​NovaServiceProvider.php Registers the SSO bypass callback.
workbench/​app/​Models/​User.php Adds SSO model support.
tests/​Feature/​MiddlewareTest.php Tests bypass behavior and callback arguments.
src/​TwoFactorManager.php Stores and evaluates bypass callbacks.
src/​NovaForceTwoFactorServiceProvider.php Registers the manager singleton.
src/​Http/​Middleware/​EnsureTwoFactorEnabled.php Applies bypass callbacks.
src/​Facades/​ForceTwoFactor.php Exposes the bypass API.
.gitignore Allows composer.lock to be tracked.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/TwoFactorManager.php
Comment on lines +47 to +49
foreach ($this->bypassCallbacks as $callback) {
if ($callback($request, $user)) {
return true;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants