Files
Qortal-Nextcloud-Integration/docs/nuqloud-identity-provider-guide.md

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:

  1. A private app redirects the user to the broker /authorize endpoint.
  2. The broker validates the client, redirect URI, requested scopes, and PKCE policy.
  3. The user completes the NuQloud login flow.
  4. The broker checks account policy and group policy server-side.
  5. The broker issues an authorization code.
  6. The app exchanges the code at /token.
  7. The broker issues short-lived tokens and records audit events.
  8. The app can call /userinfo for 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.sh ensures user_oidc and qortal_integration are present, then syncs identity-provider runtime config after the stack starts.
  • recreate-devprod.sh enables the OIDC provider, configures Nextcloud app runtime values, and verifies final sync.
  • scripts/finish-initial-setup.sh enables 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.sh syncs env-backed values into qortal_integration and the broker OIDC config.

For host-hybrid deployments:

  • scripts/install-host-nextcloud-hybrid.sh generates sidecar broker env, starts the broker, enables required host Nextcloud apps, configures user_oidc, and syncs qortal_integration runtime config.
  • scripts/update-host-nextcloud-hybrid.sh reapplies the host-hybrid installer.
  • scripts/bootstrap-host-nextcloud-hybrid.sh writes 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:

  1. Confirm broker connection succeeds.
  2. Confirm OIDC issuer URL is public and stable.
  3. Confirm the provider policy mode is correct.
  4. Confirm the internal broker token matches between env and app config.
  5. Confirm the Nextcloud user_oidc provider exists for the cloud login flow.

To register a private app:

  1. Select a template.
  2. Replace every example domain with the app's real public URL.
  3. Confirm exact redirect URI values.
  4. Choose allowed scopes.
  5. Add allowed groups if access should be limited.
  6. Enable PKCE for public/browser clients.
  7. Create the client.
  8. Copy the one-time secret immediately.
  9. Add the issuer, client ID, and secret to the relying app.
  10. 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:

  • openid
  • profile
  • email
  • groups
  • qortal_address

Recommended defaults:

  • Use openid profile email for most apps.
  • Add groups only when the app needs group-based authorization.
  • Add qortal_address only 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_TOKEN is present and matches app config.
  • OIDC_PRIVATE_KEY_PEM_B64 or OIDC_PRIVATE_KEY_PEM is 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:

  1. Disable the client in the admin UI.
  2. Fix redirect URIs, scopes, groups, or PKCE policy.
  3. Re-enable the client.
  4. Try a fresh sign-in.

If a client secret is lost:

  1. Rotate the secret in the admin UI.
  2. Copy the one-time secret.
  3. Update the relying app.
  4. Restart the relying app if it reads config only at boot.

If OIDC login to Nextcloud breaks:

  1. Use an existing local Nextcloud admin session if available.
  2. Verify user_oidc provider config.
  3. Verify OIDC_ISSUER, OIDC_CLIENT_ID, and OIDC_CLIENT_SECRET.
  4. 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:

  1. Confirm the app can reach /jwks.
  2. Confirm OIDC_PRIVATE_KEY_PEM_B64 or OIDC_PRIVATE_KEY_PEM and OIDC_KEY_ID did not change.
  3. 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.