barycenter/book/src/authentication/2fa-admin-enforced.md
Till Wegmueller 39eb8206a1
docs: Add comprehensive mdbook documentation
Complete documentation site covering all aspects of Barycenter:
Getting Started, Authentication, OAuth 2.0/OIDC, Authorization
Policy Engine, Administration, Deployment, Security, Development,
and Reference sections (96 markdown files).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 17:59:55 +01:00

4 KiB

Admin-Enforced 2FA

Admin-enforced two-factor authentication allows an administrator to mandate that a specific user must always complete a second authentication factor (passkey verification) after entering their password. This is the strongest 2FA enforcement mode -- the user cannot bypass it regardless of what they are accessing.

How It Works

  1. An administrator sets the requires_2fa flag for a user via the Admin GraphQL API.
  2. The flag is stored in the users table as requires_2fa = 1.
  3. On the user's next login, after successful password authentication, Barycenter checks the flag.
  4. If requires_2fa = 1, a partial session is created with mfa_verified = 0 and the user is redirected to /login/2fa.
  5. The user completes passkey verification.
  6. The session is upgraded to mfa_verified = 1 with acr = "aal2".

Enabling 2FA for a User

Use the setUser2faRequired GraphQL mutation on the admin API (default port 9091):

mutation {
  setUser2faRequired(username: "alice", required: true) {
    success
    message
    requires2fa
  }
}

Example using curl:

curl -X POST http://localhost:9091/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { setUser2faRequired(username: \"alice\", required: true) { success message requires2fa } }"
  }'

Response

{
  "data": {
    "setUser2faRequired": {
      "success": true,
      "message": "2FA requirement updated for user alice",
      "requires2fa": true
    }
  }
}

Disabling 2FA for a User

Pass required: false to remove the enforcement:

mutation {
  setUser2faRequired(username: "alice", required: false) {
    success
    message
    requires2fa
  }
}

This removes the mandatory 2FA requirement. The user will still be prompted for 2FA if a context-based trigger applies to a specific authorization request.

Checking a User's 2FA Status

Use the user2faStatus query to inspect whether a user has 2FA enabled and whether they have passkeys enrolled:

query {
  user2faStatus(username: "alice") {
    username
    requires2fa
    passkeyEnrolled
    passkeyCount
    passkeyEnrolledAt
  }
}

Response

{
  "data": {
    "user2faStatus": {
      "username": "alice",
      "requires2fa": true,
      "passkeyEnrolled": true,
      "passkeyCount": 2,
      "passkeyEnrolledAt": "2026-01-15T10:30:00Z"
    }
  }
}

Database Column

The enforcement flag is stored in the users table:

Column Type Description
requires_2fa Integer 0 = not required (default), 1 = required

The Redirect to /login/2fa

When Barycenter detects that 2FA is required for a user who has just authenticated with a password, it:

  1. Creates a partial session with mfa_verified = 0, amr = ["pwd"], acr = "aal1".
  2. Preserves the pending authorization request parameters in the session.
  3. Returns an HTTP redirect to /login/2fa.

The /login/2fa page presents the user with a passkey verification prompt. Upon successful verification, the session is upgraded and the user is redirected back to /authorize to continue the OAuth flow.

See 2FA Flow Walkthrough for the complete sequence.

Considerations

  • Passkey enrollment: A user must have at least one registered passkey before admin-enforced 2FA can be completed. If the user has no passkeys, they will be unable to satisfy the 2FA requirement and will be stuck at the /login/2fa page. Use the user2faStatus query to verify enrollment before enabling the flag.
  • Existing sessions: Enabling requires_2fa does not invalidate existing sessions. The flag is checked at the next login. To force re-authentication, expire the user's current sessions.
  • Admin access: The GraphQL admin API should be protected and not exposed publicly. See Admin GraphQL API for access control guidance.