Single sign-on & provisioning

NovuHub speaks two standards, so any identity provider works — Microsoft Entra ID, Okta, Google Workspace, Keycloak, Authentik, JumpCloud, OneLogin — without vendor-specific code.

Both are switched on by environment variables on the server; nothing needs to change in the app.

OpenID Connect sign-in

1. Register NovuHub at your identity provider

Create a web application client and set the redirect URI to

https://<your-novuhub-host>/auth/oidc/callback

Request the scopes openid email profile. Copy the issuer URL, client ID and client secret.

2. Configure the server

NOVUHUB_OIDC_ISSUER=https://login.example.com/realms/acme   # issuer, no trailing slash
NOVUHUB_OIDC_CLIENT_ID=novuhub
NOVUHUB_OIDC_CLIENT_SECRET=…
NOVUHUB_OIDC_SCOPES="openid email profile"                  # optional
NOVUHUB_OIDC_BUTTON_LABEL="Sign in with Acme SSO"           # optional
NOVUHUB_OIDC_AUTO_PROVISION=1   # 1 = create an account on first sign-in (default), 0 = invite-only

Restart the service. The login page now shows the SSO button; /auth/oidc/login starts the flow.

How accounts are matched

Trust model

Tokens are exchanged server-to-server over TLS; the browser never sees them. The ID token's issuer, audience, expiry and nonce are checked, and the identity is read from the IdP's userinfo endpoint and cross-checked against the token's subject. State is bound to the session and expires after 10 minutes.

SCIM 2.0 provisioning

1. Configure the server

NOVUHUB_SCIM_TOKEN=$(python3 -c "import secrets;print(secrets.token_urlsafe(32))")
NOVUHUB_SCIM_DEFAULT_ROLE=member   # role for provisioned people: member | lead | admin

2. Configure the identity provider

SettingValue
SCIM base URLhttps://<your-novuhub-host>/scim/v2
AuthenticationBearer token = NOVUHUB_SCIM_TOKEN
Unique identifieruserName (the email address)

Supported endpoints: ServiceProviderConfig, Schemas, ResourceTypes, Users (list with filter=userName eq "…", create, get, replace, patch, delete) and an empty Groups list.

What provisioning does

IdP actionNovuHub
Assign userCreates the account (verified, password-less) and adds it to the company workspace with the default role
Update name / emailUpdates the account
active: false or unassignDeactivates the account; it can no longer sign in, data is kept
active: trueReactivates
DeleteDeactivates (erasure stays a GDPR flow run by an administrator)

Groups are not modelled; section access is managed inside NovuHub.

Testing the setup

  1. Sign in through the SSO button with a test user — a new account should appear in the Directory.
  2. In the IdP, run a provisioning test / Provision on demand for a user and check GET /scim/v2/Users?filter=userName eq "user@example.com" returns it.
  3. Deactivate the user in the IdP and confirm the login is refused.

Both features write to the server log (journalctl -u novuhub) on failure with the reason, without leaking tokens.