Bug fixes & generic OIDC/SSO provider support#5494
Bug fixes & generic OIDC/SSO provider support#5494StuFrankish wants to merge 1 commit intoNginxProxyManager:developfrom
Conversation
a9fb665 to
ad3243f
Compare
|
So I missed a valid use-case - configuring NPM through environment vars for automated deployment scenarios - for the folks with more advanced homelab setups. Here are the the changes; Config FileThe container automatically looks for Sample config file{
"providers": [
{
"id": "authentik",
"name": "Authentik",
"discovery_url": "https://auth.example.com/application/o/npm/.well-known/openid-configuration",
"client_id": "npm-client",
"client_secret": "${OIDC_AUTHENTIK_SECRET}",
"scopes": "openid email profile",
"enabled": true,
"auto_provision": true,
"use_par": false,
"claim_mapping": {
"email": "email",
"name": "name",
"nickname": "preferred_username",
"avatar": "picture"
}
}
]
}Provider fieldsThese mirror the UI, so nothing new here.
Secret HandlingWhile folks can do what they like, secrets ought to be well, secret... so best practice advice is to use placeholders in the config file (Use Placeholders are resolved from environment variables at startup. Only "client_secret": "${OIDC_AUTHENTIK_SECRET}"Note: File-sourced secrets are held in memory only and are never written to the database or encrypted by the application - they rely on OS-level file permissions and container isolation for protection. Docker Compose ExamplesDefault path (recommended)services:
npm:
image: nginx-proxy-manager
volumes:
- npm-data:/data
- ./oidc-providers.json:/data/oidc-providers.json:ro
environment:
OIDC_AUTHENTIK_SECRET: "your-client-secret"
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
npm-data:Custom pathservices:
npm:
image: nginx-proxy-manager
volumes:
- npm-data:/data
- ./config:/config:ro
environment:
OIDC_CONFIG_FILE: "/config/oidc-providers.json"
OIDC_AUTHENTIK_SECRET: "your-client-secret"
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
npm-data:Environment variables only (single provider)For a single provider, no config file is needed: services:
npm:
image: nginx-proxy-manager
volumes:
- npm-data:/data
environment:
OIDC_PROVIDER_ID: "authentik"
OIDC_PROVIDER_NAME: "Authentik"
OIDC_PROVIDER_DISCOVERY_URL: "https://auth.example.com/application/o/npm/.well-known/openid-configuration"
OIDC_PROVIDER_CLIENT_ID: "npm-client"
OIDC_PROVIDER_CLIENT_SECRET: "your-client-secret"
OIDC_PROVIDER_AUTO_PROVISION: "true"
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
npm-data:Multiple providers{
"providers": [
{
"id": "authentik",
"name": "Authentik",
"discovery_url": "https://auth.example.com/application/o/npm/.well-known/openid-configuration",
"client_id": "npm-client",
"client_secret": "${OIDC_AUTHENTIK_SECRET}"
},
{
"id": "keycloak",
"name": "Keycloak",
"discovery_url": "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration",
"client_id": "npm-client",
"client_secret": "${OIDC_KEYCLOAK_SECRET}"
}
]
}Environment Variable Reference
Conflict ResolutionIf the same provider ID is defined in multiple sources, priority is:
A warning is logged when a conflict is detected. Security Notes
|
|
We're waiting for OIDC implementation already for 3 years. NOBODY CARE ABOUT IT. And your PR will be ignored. So sad... BTW: I got this with Authentik when I try to edit the provider in NPM:
And can't save changes. In the NPM logs I got: When I try to link the account, Authentik shows this: But I able to login with Authentik. |
|
Thanks for you feedback @alexsalex
That's up to @jc21 - there are no other maintainers so not much I can do but make the offer.
Thanks for letting me know, I've found two small bugs and will address them both later tonight.
Have you added both callback URI's to the config in Authentik? Paths are; I'll also add this to the "External Authentication" Settings page to make it clearer. 👍 |
…dmin UI Implements a complete OpenID Connect integration allowing users to sign in via external identity providers (Authentik, Keycloak, Authelia, Google, etc). - OIDC provider management with discovery, PKCE (S256), and encrypted client secrets - Pushed Authorization Requests (PAR) support per RFC 9126 - Account linking/unlinking with lockout prevention and 2FA compatibility - Admin settings UI with provider table, modal editor, and test connection - Auto-provisioning of new users with restricted default roles - Audit logging with per-provider change tracking - Help documentation and full i18n coverage
|
Docker Image for build 6 is available on DockerHub: Note Ensure you backup your NPM instance before testing this image! Especially if there are database changes. Warning Changes and additions to DNS Providers require verification by at least 2 members of the community! |
Don't give up, please....
No.. added. After I repull the image and add second callback URL everything start working for me as expected. I was able to link the account and edit the SSO provider in settings. |
|
Only this still appears, but it's Warning: Use Authentik. Its not affect the SSO work, just FYI. |
I'm not super familiar with Authentik, but what I could find suggests that while it is supported, PAR must be explicitly enabled on the OAuth2/OIDC provider in Authentik's admin UI - it's not on by default. Without PAR, I can't pre-validate credentials server-side during the "Test Connection" step, but login will still work fine. |
Summary
This PR contains three changes: a bug fix for Nginx config handling, a full OIDC/SSO feature implementation and a frontend email validation fix.
Closes #3678
Closes #5126
Closes #5370
Closes #5467
1. Bug Fix: Nginx config detection and error preservation (#3678)
Problem:
The
advancedConfigHasDefaultLocationfunction inbackend/internal/nginx.jshad two bugs:=,~,~*,^~)Additionally,
renameConfigAsErrorwas deleting the config file instead of preserving it as.errfor debugging and a redundantdeleteConfigcall followed immediately after.Ultimately resulting in a failure and users seeing the OpenResty welcome page.
Changes:
backend/internal/nginx.jsrenameConfigAsErrorto delete the old.errfile first then rename (preserving the config for debugging)deleteConfigcall in the error path2. Bug Fix: Email validation inconsistency (#5370)
Problem:
The frontend email validation regex in
Validations.tsxwas more permissive than the backend schema pattern incommon.json. The frontend accepted emails without a TLD (e.g.,user@localhost,user@internalserver) while the backend required a dot followed by a 2+ letter TLD. This meant users could complete registration/setup with an email the backend would later reject, potentially locking them out./^[A-Z0-9._%+-]+@[A-Z0-9.-]+$/i^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$Changes:
frontend/src/modules/Validations.tsx/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, matching the backend pattern and ensuring consistent validation across all forms (setup, login, user management)3. Feature: OpenID Connect (OIDC/SSO) provider support (#5467, #5126)
Note
I missed a valid use-case driver, so I've amended this branch and documented it in this comment below.
Feature Request:
Nginx Proxy Manager only supports local email/password authentication. Users leveraging centralized identity providers have no way to integrate SSO, forcing separate credential management.
Features Added:
Changes:
Backend
backend/internal/oidc.js- Core OIDC module: discovery with caching, PKCE-enforced auth code flow, callback handling, user resolution/auto-provisioning, account linking, test connection with PAR-based validation (credentials + scopes), fallback toscopes_supportedmetadatabackend/routes/oidc.js- API routes for providers, config CRUD, authorize, callback (HTML response with XSS-safe error whitelisting), logout, link, test-connectionbackend/lib/crypto.js- AES-256-GCM encryption for client secrets at rest, key derived via HKDF from RSA private key with purpose-bound labelbackend/internal/user.js-hasPasswordAuthflag on the user model, clear error messages for OIDC-only users attempting password operationsbackend/internal/2fa.js- OIDC-only users are blocked from 2FA enrollment (requirePasswordAuthguard) - assumption is their IdP manages security policiesbackend/migrations/20260409000000_oidc_support.js- Altersetting.valueto TEXT (for encrypted secrets in JSON), add composite index onauthtable for fast OIDC sub lookupbackend/schema/paths/oidc/- Full OpenAPI schema for all OIDC endpoints withadditionalProperties: false, HTTPS pattern enforcement,auto_provision_roleenum restricted to"user"Frontend
frontend/src/pages/Settings/OidcSettings.tsx- Settings page orchestrator with provider CRUD, dark-mode-safe table wrapperfrontend/src/pages/Settings/OidcProviderTable.tsx- Provider table using@tanstack/react-tablewith name, provider ID, status badge, and actions dropdownfrontend/src/modals/OidcProviderModal.tsx- Tabbed modal (Connection / Options / Claim Mapping) with auto-ID generation, PAR toggle, callback URL with copy button, rich test connection results (discovery pass, credentials pass/warn/fail, scopes pass/fail)frontend/src/pages/Login/index.tsx- OIDC login buttons on the login pagefrontend/src/api/backend/- API layer:getOidcConfig,getOidcProviders,updateOidcConfig,testOidcConnectionwith typedTestOidcConnectionResultfrontend/src/hooks/-useOidcConfiganduseOidcProvidersReact Query hooksfrontend/src/context/AuthContext.tsx- OIDC callback token handlingfrontend/src/components/SiteHeader.tsx- External auth indicatorfrontend/src/pages/Users/Table.tsx- External auth icon on user table rowsInfrastructure
docker/rootfs/etc/nginx/conf.d/-X-Forwarded-Portheader in dev and production nginx configsdocker/docker-compose.dev.windows.yml- Windows dev compose override with bind mountsSecurity:
A comprehensive AI-assisted security audit was performed. Key findings:
Implemented correctly:
code_verifier/code_challenge- prevents authorization code interception********) in all API responses - never sent to frontendrole: "user"(schema-enforced enum) - no privilege escalationalg=noneattackshtmlEncode(),JSON.stringify()additionalProperties: falseon all endpointsKnown non-blocking findings (defense-in-depth, not exploitable):
localStorage(pre-existing app-wide pattern)client_id(mitigated by cache-bust on save/test)Testing:
Automated Tests (
backend/test/oidc.test.js):<>&"'), XSS payload neutralizationauto_provision_roleonly allows"user"oidc-state, rejects missing/wrong/empty scopesManual Testing:
Screenshots
Login Screen
Profile & User Management
Settings