Skip to content

feat: self-hosted env flag to require MFA for every dashboard user #5025

Open

Description

@brentshulman-silkline

Is your feature request related to a problem? Please describe.

Self-hosted instances can't require multi-factor authentication. TOTP MFA is opt-in for each user, magic-link login is always available, and users can turn MFA off themselves. Operators under compliance programs (FedRAMP, SOC 2, HIPAA) need to require a second factor for every dashboard user, not just recommend one.

Describe the solution you'd like to see

An opt-in MFA_REQUIRED webapp env var, off by default. When it's set:

  • A signed-in user without MFA is sent to a setup page. Other dashboard requests are refused until they enable it.
  • Users can't disable MFA.

Describe alternate solutions

  • Put an authenticating proxy (such as OIDC at the load balancer) in front of the dashboard. This adds infrastructure, and the MFA it enforces sits outside Trigger.dev.
  • Report users without MFA and follow up with them manually. This catches gaps but doesn't prevent access.

Additional information

I have an implementation ready and will open a PR that references this issue.

Activity

  1. added a commit that references this issue on Oct 17, 2026
    7b3b867
  2. MauryaQbit commented on Oct 17, 2026

    @MauryaQbit

    For reference, I'd written an implementation of this before I saw the vouch workflow. The branch is public in case it's useful alongside your own:

    feat/mfa-required-webapp (7b3b8672b) on MauryaQbit/trigger.dev — rebased on current main, 14 files, +646/−16. My PR #5034 was auto-closed by the vouch gate, so this is offered as a reference implementation rather than a request for review.

    Design, if it's helpful to compare:

    • MFA_REQUIRED: BoolEnv.default(false); no-op when unset.
    • Layered enforcement (requireUser + the root.tsx loader) because there's no single guard for all authenticated routes; the root loader does not run for action-only resource routes, so those actions check separately.
    • The auth flow (/login*, /magic, /auth/*, /logout) and the enrollment endpoint are exempt, to avoid a redirect deadlock.
    • Disable is blocked at the service, route and UI layers.
    • Also fixed enableTotp orphaning a pending SecretReference when the forced-setup page is refreshed.
    • 14 unit tests; typecheck --filter webapp 20/20, oxfmt/oxlint/knip clean. Docker-backed suites unverified locally (no container runtime here).

    refs #5025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions