14 KiB
NuQloud Identity Provider Guide
This guide explains how to operate NuQloud as an OpenID Connect identity provider for private applications.
Use this guide when you want users to sign in to approved services such as Gitea, Grafana, Wiki.js, OpenProject, Outline, or a custom internal app using their NuQloud identity.
For the older Nextcloud-only user_oidc setup notes, see
docs/nextcloud-oidc-setup.md.
What This Provides
NuQloud can act as the identity provider for other trusted applications.
The broker owns OIDC token issuance and client policy. Nextcloud remains the admin surface where operators configure the provider, register clients, review audit events, and control account access policy.
Supported provider endpoints:
/.well-known/openid-configuration/authorize/token/userinfo/jwks
Supported client management:
- Create OIDC clients.
- Edit display name, redirect URIs, scopes, group rules, and PKCE policy.
- Disable or re-enable clients.
- Rotate client secrets.
- View recent identity-provider audit events.
- Use built-in setup templates for common apps.
Current limitations:
- Refresh tokens are not enabled.
- Token revocation is not implemented yet.
- Logout callbacks are not implemented yet.
- Redirect URI matching is exact.
- Client secrets are shown only when created or rotated.
Architecture
NuQloud identity provider flow:
- A private app redirects the user to the broker
/authorizeendpoint. - The broker validates the client, redirect URI, requested scopes, and PKCE policy.
- The user completes the NuQloud login flow.
- The broker checks account policy and group policy server-side.
- The broker issues an authorization code.
- The app exchanges the code at
/token. - The broker issues short-lived tokens and records audit events.
- The app can call
/userinfofor scoped profile claims.
Nextcloud app responsibilities:
- Admin UI for provider settings.
- Client registration UI.
- Client secret rotation.
- Audit log viewing.
- Invite and allowlist tools.
- Runtime config sync to the broker.
Broker responsibilities:
- Discovery metadata.
- OIDC authorization, token, userinfo, and JWKS endpoints.
- Client secret validation.
- Exact redirect URI enforcement.
- PKCE enforcement.
- Scope filtering.
- Group access enforcement.
- Token signing.
- Audit events.
Built-In Setup Paths
The identity provider is wired into the standard setup paths.
For dev-prod Docker deployments:
start-devprod.shensuresuser_oidcandqortal_integrationare present, then syncs identity-provider runtime config after the stack starts.recreate-devprod.shenables the OIDC provider, configures Nextcloud app runtime values, and verifies final sync.scripts/finish-initial-setup.shenables the required apps, configures the Nextcloud OIDC provider, syncs runtime settings, and records manual recovery commands if something is not ready.scripts/ensure-qortal-integration-runtime-config.shsyncs env-backed values intoqortal_integrationand the broker OIDC config.
For host-hybrid deployments:
scripts/install-host-nextcloud-hybrid.shgenerates sidecar broker env, starts the broker, enables required host Nextcloud apps, configuresuser_oidc, and syncsqortal_integrationruntime config.scripts/update-host-nextcloud-hybrid.shreapplies the host-hybrid installer.scripts/bootstrap-host-nextcloud-hybrid.shwrites the built-in provider env defaults used by the sidecar broker.
Important env keys:
OIDC_ISSUER=https://qortalbroker.example.test
OIDC_CLIENT_ID=nextcloud-local
OIDC_CLIENT_SECRET=<secret>
OIDC_REDIRECT_URI_ALLOWLIST=https://cloud.example.test/apps/user_oidc/code
OIDC_POLICY_MODE=auto_provision
OIDC_AUTO_PROVISION_GUARD=invite_or_allowlist
OIDC_REQUIRE_EMAIL_FOR_NEW_ACCOUNT=true
OIDC_BRANDING_MODE=powered
OIDC_AUTH_REQUEST_TTL_SECONDS=600
OIDC_AUTH_CODE_TTL_SECONDS=120
OIDC_ACCESS_TOKEN_TTL_SECONDS=600
OIDC_ID_TOKEN_TTL_SECONDS=600
OIDC_PRIVATE_KEY_PEM=
OIDC_PRIVATE_KEY_PEM_B64=
OIDC_KEY_ID=
Use scripts/ensure-oidc-signing-key.sh .env.devprod to generate and validate
a stable signing key. The script stores the key as OIDC_PRIVATE_KEY_PEM_B64,
which is safer for single-line env files than raw PEM text. Raw
OIDC_PRIVATE_KEY_PEM remains supported, including escaped \n line breaks.
If the broker rotates signing keys unexpectedly, existing relying parties may
reject tokens until they refresh JWKS.
Existing installs without a configured key are stabilized the next time setup, start, recreate, or host-hybrid install scripts run. If the broker was already using an in-memory generated key, that private key cannot be recovered from env; the generated env key becomes the stable key for future broker starts. Schedule the first broker restart after stabilization during a low-impact window.
First-Time Setup
Use the normal setup flow for the target deployment.
Dev-prod no-SSL:
./start-devprod.sh --mode nossl
./scripts/finish-initial-setup.sh --mode nossl --env-file .env.devprod
Dev-prod SSL:
./start-devprod.sh --mode ssl
./scripts/finish-initial-setup.sh --mode ssl --env-file .env.devprod
After setup, confirm the discovery document is reachable from the public broker URL:
curl -fsS "$(grep -m1 '^OIDC_ISSUER=' .env.devprod | cut -d= -f2-)/.well-known/openid-configuration"
Confirm Nextcloud has the required apps enabled:
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod exec -T --user www-data app php occ app:list | rg 'qortal_integration|user_oidc'
For SSL mode, use docker-compose.devprod.yml with the same .env.devprod
file.
Admin UI Workflow
Open Nextcloud Administration settings and select the Qortal Integration admin section.
Before adding private apps:
- Confirm broker connection succeeds.
- Confirm OIDC issuer URL is public and stable.
- Confirm the provider policy mode is correct.
- Confirm the internal broker token matches between env and app config.
- Confirm the Nextcloud
user_oidcprovider exists for the cloud login flow.
To register a private app:
- Select a template.
- Replace every example domain with the app's real public URL.
- Confirm exact redirect URI values.
- Choose allowed scopes.
- Add allowed groups if access should be limited.
- Enable PKCE for public/browser clients.
- Create the client.
- Copy the one-time secret immediately.
- Add the issuer, client ID, and secret to the relying app.
- Complete a sign-in and confirm an audit event appears.
The generated setup output in the admin UI shows the issuer, discovery URL, client ID, scopes, auth method, and template-specific notes.
Client Templates
Templates prefill common values only. Always replace placeholder domains and callback paths with the real values from the relying app.
Gitea
Template defaults:
Client ID: gitea
Redirect URI: https://git.example.com/user/oauth2/NuQloud/callback
Scopes: openid profile email
Use a stable authentication source name in Gitea. That name becomes part of the
callback URL. Gitea can also be configured from the command line with
gitea admin auth add-oauth.
Official docs: https://docs.gitea.com/administration/command-line
Grafana
Template defaults:
Client ID: grafana
Redirect URI: https://grafana.example.com/login/generic_oauth
Scopes: openid profile email groups
Use Grafana generic OAuth settings. Configure auth URL, token URL, and API URL from NuQloud discovery metadata.
Official docs: https://grafana.com/docs/grafana/latest/setup-grafana/configure-access/configure-authentication/generic-oauth/
Wiki.js
Template defaults:
Client ID: wikijs
Redirect URI: https://wiki.example.com/login/<provider-callback>
Scopes: openid profile email groups
Copy the exact callback URL shown by Wiki.js into the NuQloud client.
Official docs: https://docs.requarks.io/auth
OpenProject
Template defaults:
Client ID: openproject
Redirect URI: https://projects.example.com/auth/<provider-slug>/callback
Scopes: openid profile email
Copy the exact redirect URI shown by OpenProject. Provider slugs can change the path.
Official docs: https://www.openproject.org/docs/system-admin-guide/authentication/openid-providers/
Outline
Template defaults:
Client ID: outline
Redirect URI: https://docs.example.com/auth/oidc.callback
Scopes: openid profile email
Configure Outline with the NuQloud issuer/discovery URL, client ID, and client secret. Restart Outline after changing OIDC env values.
Compatibility note: NuQloud does not issue refresh tokens yet. If your Outline
version or deployment requires offline_access or refresh tokens, defer Outline
SSO until refresh-token support is added.
Official docs: https://docs.getoutline.com/s/hosting/doc/oidc-8CPBm6uC0I
Generic OIDC App
Template defaults:
Client ID: private-app
Redirect URI: https://app.example.com/oidc/callback
Scopes: openid profile email
PKCE: enabled
Use this for internal tools, desktop apps, and browser clients. Keep PKCE on for public clients.
Claims And Scopes
The broker releases only claims allowed by the registered client scopes.
Supported scopes:
openidprofileemailgroupsqortal_address
Recommended defaults:
- Use
openid profile emailfor most apps. - Add
groupsonly when the app needs group-based authorization. - Add
qortal_addressonly for apps that explicitly need Qortal identity data.
Powered Mode default:
- Use NuQloud-facing labels in the user experience.
- Do not expose Qortal-specific claims unless the client requires them.
Full Qortal Mode:
- Qortal-specific labels and claims are allowed when policy permits them.
Never rely on client-side filtering for access control. Enforce access using the registered client's allowed groups and server-side policy.
Security Checklist
Before calling an instance ready:
- Redirect URIs are exact HTTPS URLs for production apps.
- Client secrets are copied once and not stored in browser-visible notes.
- Disabled clients cannot authorize or exchange tokens.
- Secret rotation invalidates the old client secret.
- Public clients require PKCE.
- Allowed scopes are minimal.
- Allowed groups are set for restricted apps.
BROKER_INTERNAL_API_TOKENis present and matches app config.OIDC_PRIVATE_KEY_PEM_B64orOIDC_PRIVATE_KEY_PEMis set for production stability.- Broker and Nextcloud public URLs match actual reverse-proxy routing.
- No secrets appear in client-side UI, public logs, or copied setup notes.
Admin endpoints are authenticated through the Nextcloud app and proxied to the broker with the internal broker token. Do not expose broker admin APIs publicly without the internal-token boundary.
Recovery And Rollback
If a client is misconfigured:
- Disable the client in the admin UI.
- Fix redirect URIs, scopes, groups, or PKCE policy.
- Re-enable the client.
- Try a fresh sign-in.
If a client secret is lost:
- Rotate the secret in the admin UI.
- Copy the one-time secret.
- Update the relying app.
- Restart the relying app if it reads config only at boot.
If OIDC login to Nextcloud breaks:
- Use an existing local Nextcloud admin session if available.
- Verify
user_oidcprovider config. - Verify
OIDC_ISSUER,OIDC_CLIENT_ID, andOIDC_CLIENT_SECRET. - Re-run setup sync:
./scripts/finish-initial-setup.sh --mode nossl --env-file .env.devprod
./scripts/ensure-qortal-integration-runtime-config.sh --compose-file docker-compose.devprod.nossl.yml --env-file .env.devprod
For SSL mode, use --mode ssl and docker-compose.devprod.yml.
If a relying app rejects tokens after broker restart:
- Confirm the app can reach
/jwks. - Confirm
OIDC_PRIVATE_KEY_PEM_B64orOIDC_PRIVATE_KEY_PEMandOIDC_KEY_IDdid not change. - Restart the relying app or clear its JWKS cache if needed.
Devcloud Verification
Run these after code, env, or setup-script changes.
Static checks:
bash -n start-devprod.sh recreate-devprod.sh scripts/finish-initial-setup.sh scripts/bootstrap-host-nextcloud-hybrid.sh scripts/install-host-nextcloud-hybrid.sh scripts/ensure-qortal-integration-runtime-config.sh
./scripts/ensure-oidc-signing-key.sh .env.devprod
node --check nextcloud/custom_apps/qortal_integration/js/admin.js
npm --prefix services/qortal-oidc-broker run build
Runtime sync:
./scripts/finish-initial-setup.sh --mode nossl --env-file .env.devprod
./scripts/ensure-qortal-integration-runtime-config.sh --compose-file docker-compose.devprod.nossl.yml --env-file .env.devprod
Discovery:
curl -fsS "$(grep -m1 '^OIDC_ISSUER=' .env.devprod | cut -d= -f2-)/.well-known/openid-configuration"
App enablement:
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod exec -T --user www-data app php occ app:list | rg 'qortal_integration|user_oidc'
Admin UI checks:
- Create one client from a template.
- Copy the one-time secret.
- Edit redirect URIs and save.
- Rotate the secret.
- Disable and re-enable the client.
- Complete one app login.
- Confirm audit events show authorization and token activity.
Completion Criteria
Call the identity-provider feature complete when:
- Built-in setup scripts configure the provider without manual file edits.
- The admin UI can create, edit, disable, enable, and rotate client secrets.
- Client secrets are not exposed after creation or rotation.
- Exact redirect validation is confirmed.
- Group-denied users cannot authorize restricted clients.
- Scope filtering is confirmed through
/userinfo. - Audit events are visible after auth and token actions.
- Devcloud runtime verification passes.
- This guide reflects the tested setup path.