OIDC Integration
nextExplorer uses Express OpenID Connect (EOC) to federate authentication with external providers. Configure these variables and your IdP once, and the app exposes /login, /callback, and /logout to manage the flow.
Environment variables (see backend/src/config/env.js)
OIDC_ENABLED=trueenables the middleware.OIDC_ISSUERpoints to the IdP discovery URL (e.g., Keycloak realm or Authentik application base).OIDC_CLIENT_IDandOIDC_CLIENT_SECRETstore client credentials.OIDC_SCOPESdefaults toopenid profile email; addgroupsif you want nextExplorer to inspect group claims.OIDC_ADMIN_GROUPScontains comma/space-separated group names that grant the admin role when present ingroups,roles, orentitlementsclaims.OIDC_REQUIRE_EMAIL_VERIFIED(defaultfalse) — whentrue, requires the IdP to verify the user's email before allowing user creation or auto-linking. Some providers like newer versions of Authentik setemail_verifiedtofalseby default; keep this setting asfalseto allow those users to log in.OIDC_AUTO_CREATE_USERS(defaulttrue) — whenfalse, the user must already exist in the nextExplorer database (local or previously OIDC-linked), otherwise OIDC login is denied.- Optional overrides:
OIDC_AUTHORIZATION_URL,OIDC_TOKEN_URL,OIDC_USERINFO_URL,OIDC_LOGOUT_URL, and an explicitOIDC_CALLBACK_URL(defaults to${PUBLIC_URL}/callback).OIDC_LOGOUT_URL— optional custom IdP logout URL. When set, logout requests redirect to this URL with apost_logout_redirect_uriparameter (OIDC standard). If not set, logout only clears the local session without redirecting to the IdP.
Choosing authentication modes
Use AUTH_MODE to control which authentication methods are available:
AUTH_MODE=oidc— OIDC only: The login page shows only the "Continue with Single Sign-On" button. Users cannot create local passwords.AUTH_MODE=local— Local only: The login page shows only username/password fields. OIDC is disabled even ifOIDC_ENABLED=true.AUTH_MODE=both— Dual authentication (default): Users can choose between local login or SSO. The login page displays both options.AUTH_MODE=disabled— No authentication: Skips the login page entirely and makes all APIs public (same asAUTH_ENABLED=false).
Flow overview
- A user clicks “Continue with Single Sign-On” on the login page.
- The app redirects to
${OIDC_AUTHORIZATION_URL}or the issuer discovery endpoint. - After IdP authentication, the callback (
/callback) is invoked, sessions are established, and the user lands back in the workspace. - Logout routes (
/logout) tear down the session. IfOIDC_LOGOUT_URLis configured, logout redirects to the IdP logout endpoint with apost_logout_redirect_uriparameter to complete the IdP logout flow. Otherwise, only the local session is cleared.
Admin elevation
- nextExplorer inspects the
groups,roles, andentitlementsclaims returned by the IdP. - If any entry matches
OIDC_ADMIN_GROUPS(case-insensitive), the user is promoted to admin. - Without a match, the user receives the standard
userrole and only sees non-admin settings.
This is re-evaluated at every sign-in, so removing someone from the admin group at the IdP takes their admin rights away here the next time they log in, and adding them grants it. Role changes are written to the log.
Two conditions have to hold before the IdP is allowed to decide, and both exist to stop a misconfiguration from locking everyone out:
OIDC_ADMIN_GROUPSmust be configured. Without it every login would derive the plainuserrole, and applying that would strip the rights of anyone promoted from the interface — the bootstrap account included.- The IdP must actually return a group claim. A missing
groupsscope looks exactly like a user who belongs to no group; roles are left untouched rather than reset on that silence.
Where neither holds, roles stay as they are and are managed from Settings → Users instead. If you do lock yourself out, setting AUTH_ADMIN_EMAIL to your address and restarting restores the admin role on that account.
Common troubleshooting
- Invalid redirect URI: Ensure your IdP’s redirect URI matches
${PUBLIC_URL}/callbackor the explicitly configuredOIDC_CALLBACK_URL. - Sessions drop after restart: Supply a stable
SESSION_SECRETinstead of letting the app generate one dynamically. - Not an admin after login: Verify the IdP includes the expected group claim (e.g.,
groupsscope) and thatOIDC_ADMIN_GROUPScontains the group name exactly. Both are required before the IdP may set roles at all — without them the role stored on the account is kept, whatever the claims say. - Cookies flagged Insecure: Run the app over HTTPS (
PUBLIC_URLmust usehttps) and confirm your proxy forwardsX-Forwarded-Proto/Hostheaders (see the Reverse Proxy guide).
