Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/NavigationDocs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,10 @@ export const docsNavigation = [
title: 'Disable Local Auth',
href: '/selfhosted/identity-providers/disable-local-authentication',
},
{
title: 'Enable MFA for local users',
href: '/selfhosted/identity-providers/enable-local-mfa'
},
{
title: 'Self-hosted IdPs',
isOpen: true,
Expand Down
7 changes: 7 additions & 0 deletions src/pages/selfhosted/configuration-files.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,13 @@ Configures the built-in identity provider (embedded IdP) that handles user authe
<Property name="server.auth.owner.password" type="string">
Password for the initial admin user. Optional. Used together with `owner.email` to bootstrap the first admin account on initial deployment.
</Property>
<Property name="server.auth.mfaSessionMaxLifetime" type="string">
Maximum MFA session duration from creation. After this time, local users must re-authenticate with TOTP regardless of activity. Default: `"24h"`. Only applicable when [local MFA](/selfhosted/identity-providers/enable-local-mfa) is enabled.
</Property>
<Property name="server.auth.mfaSessionIdleTimeout" type="string">
MFA session idle timeout. If the user is inactive for this duration, the MFA session expires and they must re-authenticate with TOTP. Default: `"1h"`. Only applicable when [local MFA](/selfhosted/identity-providers/enable-local-mfa) is enabled.
</Property>

</Properties>

When the embedded IdP is active, the server automatically hosts these OIDC endpoints:
Expand Down
116 changes: 116 additions & 0 deletions src/pages/selfhosted/identity-providers/enable-local-mfa.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import {Note, Warning} from "@/components/mdx"

export const description = "Enable MFA for local users in your self-hosted NetBird deployment so that all users have to complete a TOTP challenge to login";

# Enable MFA for local users

NetBird supports multi-factor authentication (MFA) for local users managed by the embedded identity provider. When enabled, all local users are required to set up and verify a time-based one-time password (TOTP) using an authenticator app before they can log in.

This is useful when you want to add an extra layer of security to local users, as it will require **all** local users to authenticate using the TOTP code on every login.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Behavior statement conflicts with MFA session semantics.

Line 9 says users must enter TOTP on every login, but the MFA session section (Lines 58-62) says users can skip MFA while the session is active. Please align this wording to avoid misleading operators.

Suggested wording
-This is useful when you want to add an extra layer of security to local users, as it will require **all** local users to authenticate using the TOTP code on every login.
+This is useful when you want to add an extra layer of security to local users, as it requires **all** local users to complete TOTP during sign-in whenever their MFA session is not active.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
This is useful when you want to add an extra layer of security to local users, as it will require **all** local users to authenticate using the TOTP code on every login.
This is useful when you want to add an extra layer of security to local users, as it requires **all** local users to complete TOTP during sign-in whenever their MFA session is not active.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/selfhosted/identity-providers/enable-local-mfa.mdx` at line 9,
Update the opening behavior sentence to match the "MFA session" section: change
the claim that TOTP is required "on every login" to state that TOTP is required
for each authentication unless an active MFA session is present (referencing the
"MFA session" section describing session-based skipping); ensure the text makes
clear the first login or any authentication after session expiry always requires
TOTP while active sessions allow skipping MFA until they expire.


<Note>
MFA enforcement applies only to local users authenticated through the embedded IdP. Users who sign in via external identity providers (Google, Microsoft, Okta, etc.) are not affected, as MFA for those users should be configured in the respective IdP.
</Note>

## Prerequisites

- A self-hosted NetBird deployment using the [embedded identity provider](/selfhosted/identity-providers/local)
- Local authentication must be enabled (not [disabled](/selfhosted/identity-providers/disable-local-authentication))
- Admin or Owner access to the NetBird Dashboard

## Enabling MFA

1. Log in to the NetBird Dashboard as an Admin or Owner
2. Navigate to **Settings** → **Authentication**
3. Toggle **Local MFA** to on
4. Click **Save**

Once enabled, all local users will be prompted to set up TOTP on their next login.

## User experience

### First login after MFA is enabled

When a local user logs in for the first time after MFA is enabled, they are presented with a TOTP setup screen:

1. The user sees a QR code and is prompted to scan it with an authenticator app (e.g., Google Authenticator, Authy, 1Password)
2. After scanning, the user enters the one-time code generated by their authenticator app
3. The user clicks **Verify** to complete the setup

<p>
<img src="/docs-static/img/selfhosted/identity-providers/local-mfa/totp-setup.png" alt="TOTP Setup - Scan QR code with authenticator app" className="imagewrapper"/>
</p>

### Subsequent logins

After the initial setup, every login requires a TOTP verification step:

1. The user enters their email and password as usual
2. A second screen prompts for the one-time code from their authenticator app
3. The user enters the code and clicks **Verify** to complete the login

<p>
<img src="/docs-static/img/selfhosted/identity-providers/local-mfa/totp-verify.png" alt="TOTP Verification - Enter code from authenticator app" className="imagewrapper"/>
</p>

## MFA session configuration

NetBird will hold an MFA session after a user went through the whole authentication process, this session will let users skip the MFA authentication process
as long as the session is active.

By default, MFA sessions last up to 24 hours and expire after 1 hour of inactivity. You can customize these values depending on your deployment type.

| Setting | Description | Default |
|---------|-------------|---------|
| `mfaSessionMaxLifetime` | Maximum session duration from creation. After this time, the user must re-authenticate with MFA regardless of activity. | `24h` |
| `mfaSessionIdleTimeout` | Idle timeout. If the user is inactive for this duration, the MFA session expires and they must re-authenticate. | `1h` |

### Combined setup (config.yaml)

```yaml
server:
auth:
mfaSessionMaxLifetime: "24h"
mfaSessionIdleTimeout: "1h"
```

Restart the server after changing these values:

```bash
docker compose restart netbird-server
```

### Older multi-container setup (management.json)

<Note>
This section applies to deployments using the older multi-container architecture. If you deployed using `getting-started.sh`, you are on the combined setup and should use the `config.yaml` instructions above. See the [migration guide](/selfhosted/migration/combined-container) to upgrade.
</Note>

```json
{
"EmbeddedIdP": {
"Enabled": true,
"MfaSessionMaxLifetime": "24h",
"MfaSessionIdleTimeout": "1h"
}
}
```

Restart the Management service after changing these values:

```bash
docker compose restart management
```

## Disabling MFA

To disable MFA for local users:

1. Navigate to **Settings** → **Authentication**
2. Toggle **Local MFA** to off
3. Click **Save**

<Warning>
Disable MFA removes the TOTP requirement but **does not** remove the stored TOTP authenticator information. If you enable MFA again
previously enrolled users will be prompted for the same authenticator they registered previously.
Comment on lines +114 to +115

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify the warning sentence grammar.

The warning text is grammatically off and harder to parse in a security-sensitive section.

Suggested wording
-Disable MFA removes the TOTP requirement but **does not** remove the stored TOTP authenticator information. If you enable MFA again 
-previously enrolled users will be prompted for the same authenticator they registered previously. 
+Disabling MFA removes the TOTP requirement but **does not** remove stored authenticator enrollment data. If you enable MFA again, previously enrolled users will be prompted to use the same authenticator.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Disable MFA removes the TOTP requirement but **does not** remove the stored TOTP authenticator information. If you enable MFA again
previously enrolled users will be prompted for the same authenticator they registered previously.
Disabling MFA removes the TOTP requirement but **does not** remove stored authenticator enrollment data. If you enable MFA again, previously enrolled users will be prompted to use the same authenticator.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/selfhosted/identity-providers/enable-local-mfa.mdx` around lines
114 - 115, The warning sentence "Disable MFA removes the TOTP requirement but
**does not** remove the stored TOTP authenticator information. If you enable MFA
again previously enrolled users will be prompted for the same authenticator they
registered previously." is awkward and should be replaced with a clearer,
grammatically correct phrasing; update the text in
src/pages/selfhosted/identity-providers/enable-local-mfa.mdx to something like:
"Disabling MFA removes the TOTP requirement but does not delete stored TOTP
authenticator data; if you re-enable MFA, previously enrolled users will be
prompted to use the same authenticator they registered earlier." Ensure the new
sentence preserves the original security warning and punctuation for clarity.

</Warning>
Loading