This app adds flexible, enterprise-grade multi-factor authentication to Nextcloud.
It enables Nextcloud to perform MFA against the privacyIDEA server in your network.
PrivacyIDEA supports classic OTP tokens, and challenge-response tokens like E-Mail, SMS, PUSH, or WebAuthn.
privacyIDEA Nextcloud App is now available in the Nextcloud App Store.
You can install it from the Nextcloud Admin Panel. For more information see the Nextcloud documentation: https://docs.nextcloud.com/server/stable/admin_manual/apps_management.html
- Download
privacyidea.tar.gzarchive from the latest release. - Unpack the archive to the Nextcloud apps directory:
tar -xzf privacyidea.tar.gz -C <nextcloud>/apps/. - Enable the app in the Nextcloud WebUI: go to settings(admin) -> apps -> disabled page with "Not enabled" apps and click "Enable" for the privacyIDEA application.
The app ships its js/ as-is — there is no build step.
- Copy the files of this repository to
<nextcloud>/apps/privacyidea. - In the Nextcloud WebUI go to settings(admin) -> apps -> disabled page with "Not enabled" apps and click "Enable" for the privacyIDEA application.
All settings live in Nextcloud under Settings → Administration → privacyIDEA
(or scriptable via occ config:app:set privacyidea <key> --value=<value>). At a
minimum, set the server URL and tick Activate privacyIDEA.
| Setting | Key | Description |
|---|---|---|
| Activate privacyIDEA | piActivatePI |
Master switch for MFA via privacyIDEA. Configure the server connection before enabling. |
| URL of the privacyIDEA server | piURL |
Base URL of your privacyIDEA instance, e.g. https://pi.example.com. |
| SSL certificate verification | piSSLVerify |
Verify the server's TLS certificate (host and peer). Keep enabled in production. |
| Realm | piRealm |
privacyIDEA realm to authenticate against, if not the default. |
| Timeout | piTimeout |
Request timeout in seconds (default 15; connection setup is capped at 5s). Prevents an unresponsive server from hanging the login page. |
| No proxy | piNoProxy |
Ignore the system-wide proxy and talk to privacyIDEA directly. |
| Forward client IP | piForwardClientIP |
Send the user's IP as the client parameter so privacyIDEA policies can match on the original address. |
| Setting | Key | Description |
|---|---|---|
| Exclude IP addresses | piExcludeIPs |
Skip MFA for these IPv4 addresses/ranges, e.g. 10.0.1.12,10.0.1.20-10.0.1.40. (IPv4 only; non-IPv4 or unparseable entries are ignored and never skip MFA.) |
| Group names + Include/Exclude | piInExGroupsField, piInOrExSelected |
Restrict MFA to (Include) or skip it for (Exclude) members of the listed Nextcloud groups (comma-separated). |
The Authentication flow radios (piSelectedAuthFlow) control what is sent to
privacyIDEA before the login screen is shown — used to trigger the user's token
challenges (or complete authentication) up front. Mutually exclusive:
| Flow (setting value) | What happens | Extra settings |
|---|---|---|
None (prompt only) — default (piAuthFlowDefault) |
Nothing is sent up front; the login screen is shown and whatever the user submits goes to /validate/check. Any challenges the server returns are then shown. |
— |
Trigger Challenge (piAuthFlowTriggerChallenge) |
On page load the app uses a service account to call /validate/triggerchallenge for the user, so all of the user's challenges (push, SMS, email, …) are triggered up front. |
Service name + Service password (Service realm optional). |
Send Password (piAuthFlowSendPassword) |
On page load the app sends the user's Nextcloud login password to /validate/check — completing login (e.g. passthru) or triggering challenges. Password logins only; for SSO/passkey/token logins it falls back to prompting. |
— |
Send Static Pass (piAuthFlowSendStaticPass) |
On page load the app sends a fixed configured password to /validate/check — completing login (e.g. passOnNoToken) or triggering challenges. |
Static password. |
The input layout on the login screen (single OTP field, or a separate password/PIN field plus OTP) is a separate Login screen setting — see below.
| Setting | Key | Description |
|---|---|---|
| Input layout | piInputLayout |
Login-screen layout: a single OTP field (otp, default) or a separate password/PIN field plus an OTP field (separate), combined and sent to privacyIDEA. |
| OTP field hint | piOTPFieldHint |
Placeholder text shown in the OTP input field (default "One-Time-Password"). |
| Password/PIN field hint | piPassFieldHint |
Placeholder text shown in the Password/PIN field of the separate layout (default "Password/PIN"). |
| Auto-submit by OTP length | piActivateAutoSubmitOtpLength, piAutoSubmitOtpLength |
Submit the form automatically once the configured number of characters (default 6) is entered in the OTP field. |
| Poll in browser | piPollInBrowser, piPollInBrowserURL |
For PUSH tokens, poll privacyIDEA directly from the browser so the page advances the moment the user confirms, instead of periodic page reloads. Requires a privacyIDEA URL reachable from the browser. |
| Forward headers to privacyIDEA | piForwardHeaders |
Comma-separated list of request header names to forward to privacyIDEA (useful for header-based policies). |
Go to your Nextcloud installation directory and run one of the following commands:
sudo -u www-data php occ app:enable privacyideasudo -u www-data php occ app:disable privacyidea
Nextcloud evaluates whether MFA applies to a user only once and caches the result in its two-factor provider registry, so enabling or reconfiguring the app does not retroactively affect users who are already logged in. To force Nextcloud to re-evaluate this on the next login, clear the cached state:
sudo -u www-data php occ twofactorauth:cleanup privacyidea
Existing sessions that already passed login are not challenged retroactively; the re-evaluation happens the next time the affected users log in.
A throwaway Nextcloud for testing the app is provided via Docker Compose. It
runs on SQLite (no separate database), auto-installs on first boot, and
bind-mounts this repository as the privacyidea app (auto-enabled), so your
changes are live without a rebuild. You still need your own reachable
privacyIDEA server; set its URL in the admin settings after logging in.
docker compose -f docker-compose.dev.yml up -d # start (Nextcloud "stable")
NC_VERSION=latest docker compose -f docker-compose.dev.yml up -d # test the newest release
docker compose -f docker-compose.dev.yml down -v # stop and wipeThen open http://localhost:8080 and log in as admin / admin. The Nextcloud
version is just the NC_VERSION image tag. See dev/README.md
for details (version switching, running occ, logs).
The PHP test suite and static analysis run via Composer:
composer install
composer run lint # php -l
composer run cs:check # coding standard (composer run cs:fix to apply)
composer run psalm # static analysis
composer run test:unit # PHPUnit