455 lines
12 KiB
Markdown
455 lines
12 KiB
Markdown
# NuQloud Identity Provider
|
|
|
|
## Purpose
|
|
|
|
Turn a NuQloud instance into a primary authentication and identity server for
|
|
private self-hosted services.
|
|
|
|
The goal is that a user account on a NuQloud instance can authenticate into
|
|
other trusted apps through standard OpenID Connect (OIDC), while retaining the
|
|
Qortal-powered ownership model already used by the current broker login flow.
|
|
|
|
## Short Version
|
|
|
|
NuQloud should become an OIDC Identity Provider.
|
|
|
|
Recommended direction:
|
|
|
|
1. Use the existing `qortal-oidc-broker` as the identity provider core.
|
|
2. Keep Nextcloud as the user/admin/account-management surface.
|
|
3. Register other private services as OIDC clients.
|
|
4. Issue scoped identity claims based on NuQloud account state, group policy,
|
|
and linked Qortal identity proof.
|
|
|
|
This avoids making Nextcloud itself the final identity authority. Nextcloud can
|
|
still be the visible control surface, but the broker should own token issuance,
|
|
client policy, redirect validation, identity mapping, and future service-level
|
|
access rules.
|
|
|
|
## Product Shape
|
|
|
|
Primary user outcome:
|
|
|
|
- A user logs into a NuQloud instance once.
|
|
- The same identity can sign into approved private apps.
|
|
- The user does not need separate passwords for each service.
|
|
- Admins can decide which users or groups can access which services.
|
|
|
|
Primary admin outcome:
|
|
|
|
- Admin can add a private app as an OIDC client.
|
|
- Admin can configure redirect URIs, scopes, group access, and display label.
|
|
- Admin can disable a service without deleting user identities.
|
|
- Admin can audit which users authenticated to which services.
|
|
|
|
## Architecture
|
|
|
|
### NuQloud Broker
|
|
|
|
The broker becomes the identity provider.
|
|
|
|
Responsibilities:
|
|
|
|
- OIDC discovery:
|
|
- `/.well-known/openid-configuration`
|
|
- Authorization:
|
|
- `/authorize`
|
|
- Token exchange:
|
|
- `/token`
|
|
- User info:
|
|
- `/userinfo`
|
|
- Signing keys:
|
|
- `/jwks`
|
|
- Client registration and policy storage.
|
|
- Redirect URI validation.
|
|
- Authorization code issuance.
|
|
- Access token and ID token issuance.
|
|
- Scope and claim filtering.
|
|
- Login/session handoff to Qortal-powered identity proof.
|
|
- Audit events for authentication and token activity.
|
|
|
|
### Nextcloud App
|
|
|
|
Nextcloud remains the primary UI surface.
|
|
|
|
Responsibilities:
|
|
|
|
- Admin UI for identity provider settings.
|
|
- OIDC client registration UI.
|
|
- Service access policy UI.
|
|
- User/group mapping UI.
|
|
- Audit log viewing.
|
|
- User self-service identity linking.
|
|
- Product language mode display.
|
|
|
|
Non-responsibilities:
|
|
|
|
- Signing OIDC tokens.
|
|
- Storing client secrets in browser-visible state.
|
|
- Trusting client-side access decisions.
|
|
|
|
### Qortal External Auth
|
|
|
|
External Auth remains the proof and signing layer.
|
|
|
|
Responsibilities:
|
|
|
|
- Prove identity ownership.
|
|
- Support login challenge flows.
|
|
- Support future signed approval flows.
|
|
- Avoid exposing sensitive secrets to Nextcloud UI or client apps.
|
|
|
|
### Private Apps
|
|
|
|
Private apps are OIDC relying parties.
|
|
|
|
Examples:
|
|
|
|
- Gitea
|
|
- GitLab
|
|
- OpenProject
|
|
- Grafana
|
|
- Wiki.js
|
|
- Outline
|
|
- Custom internal apps
|
|
|
|
Integration paths:
|
|
|
|
1. Native OIDC support in the app.
|
|
2. OIDC-aware reverse proxy for apps without native OIDC.
|
|
3. Future NuQloud app launcher with preconfigured client templates.
|
|
|
|
## Identity Model
|
|
|
|
NuQloud should expose stable identities that do not break when a user changes
|
|
display name, email, or linked service labels.
|
|
|
|
Recommended subject model:
|
|
|
|
- Internal subject:
|
|
- stable broker identity ID
|
|
- Public OIDC `sub`:
|
|
- stable per issuer
|
|
- never derived directly from mutable display values
|
|
- Optional claims:
|
|
- `preferred_username`
|
|
- `name`
|
|
- `email`
|
|
- `email_verified`
|
|
- `groups`
|
|
- `nuqloud_account_id`
|
|
- `qortal_address` when policy allows
|
|
|
|
Powered Mode default:
|
|
|
|
- Hide protocol-native wording from normal users.
|
|
- Present this as NuQloud identity.
|
|
- Only expose Qortal-specific claims to clients explicitly allowed by policy.
|
|
|
|
Full Qortal Mode:
|
|
|
|
- Allow Qortal-native claims and UI labels where appropriate.
|
|
- Keep claim release controlled per client.
|
|
|
|
## Client Registry
|
|
|
|
Add a broker-side OIDC client registry.
|
|
|
|
Minimum fields:
|
|
|
|
- `client_id`
|
|
- `client_secret_hash`
|
|
- `display_name`
|
|
- `redirect_uris`
|
|
- `post_logout_redirect_uris`
|
|
- `allowed_scopes`
|
|
- `allowed_groups`
|
|
- `enabled`
|
|
- `require_pkce`
|
|
- `created_by`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
Security rules:
|
|
|
|
- Redirect URIs must be exact-match allowlisted.
|
|
- Client secrets must be hashed at rest.
|
|
- Public clients must require PKCE.
|
|
- Confidential clients should support secret rotation.
|
|
- Disabled clients must fail authorization and token exchange.
|
|
|
|
## Sessions And Tokens
|
|
|
|
Initial MVP can use short-lived authorization codes and short-lived tokens.
|
|
|
|
Recommended defaults:
|
|
|
|
- Authorization code TTL: 2 minutes.
|
|
- ID token TTL: 10 minutes.
|
|
- Access token TTL: 10 minutes.
|
|
- Refresh tokens: disabled for MVP.
|
|
- PKCE: required for public clients, optional but recommended for confidential
|
|
clients.
|
|
|
|
Later phases can add:
|
|
|
|
- Refresh tokens.
|
|
- Token revocation.
|
|
- Back-channel logout.
|
|
- Front-channel logout.
|
|
- Device/session management.
|
|
- Per-client session duration.
|
|
|
|
## Access Policy
|
|
|
|
Policy must be enforced server-side by the broker.
|
|
|
|
Policy inputs:
|
|
|
|
- NuQloud account status.
|
|
- Linked identity status.
|
|
- Nextcloud user ID.
|
|
- Nextcloud groups.
|
|
- Client allowlist.
|
|
- Requested scopes.
|
|
- Admin-defined service access rules.
|
|
|
|
Policy outputs:
|
|
|
|
- Allow authorization.
|
|
- Deny authorization.
|
|
- Require re-authentication.
|
|
- Require identity proof refresh.
|
|
- Require admin approval or invite.
|
|
|
|
## Data Model
|
|
|
|
Suggested broker tables:
|
|
|
|
- `identity_subject`
|
|
- `id`
|
|
- `nextcloud_user_id`
|
|
- `primary_qortal_address`
|
|
- `status`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
- `oidc_client`
|
|
- `id`
|
|
- `client_id`
|
|
- `client_secret_hash`
|
|
- `display_name`
|
|
- `enabled`
|
|
- `require_pkce`
|
|
- `created_by`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
- `oidc_client_redirect_uri`
|
|
- `client_id`
|
|
- `redirect_uri`
|
|
|
|
- `oidc_client_scope`
|
|
- `client_id`
|
|
- `scope`
|
|
|
|
- `oidc_client_group_policy`
|
|
- `client_id`
|
|
- `group_id`
|
|
- `policy`
|
|
|
|
- `oidc_auth_code`
|
|
- `code_hash`
|
|
- `client_id`
|
|
- `subject_id`
|
|
- `redirect_uri`
|
|
- `scope`
|
|
- `pkce_challenge`
|
|
- `expires_at`
|
|
- `consumed_at`
|
|
|
|
- `oidc_audit_event`
|
|
- `event_type`
|
|
- `client_id`
|
|
- `subject_id`
|
|
- `ip_hash`
|
|
- `user_agent_hash`
|
|
- `metadata_json`
|
|
- `created_at`
|
|
|
|
## Delivery Plan
|
|
|
|
### Phase 0: Branch Start
|
|
|
|
Status:
|
|
|
|
- Branch: `feature/nuqloud-identity-provider`
|
|
- First implementation slice: broker-side client registry with hashed secrets,
|
|
exact redirect URI matching, per-client scopes, enable/disable, and secret
|
|
rotation.
|
|
|
|
### Phase 1: Provider Hardening
|
|
|
|
Outcome:
|
|
|
|
- Existing broker OIDC flow becomes suitable for multiple clients.
|
|
|
|
Work:
|
|
|
|
- Keep current durable auth request/code storage.
|
|
- Add client registry. Started.
|
|
- Enforce exact redirect URI validation. Started.
|
|
- Add hashed client secrets. Started.
|
|
- Add client update and disable controls. Started.
|
|
- Add PKCE enforcement per client. Started.
|
|
- Add per-client scopes. Started.
|
|
- Add group policy checks. Started.
|
|
- Add scoped claim release. Started.
|
|
- Add audit events. Started.
|
|
|
|
Exit criteria:
|
|
|
|
- Nextcloud still logs in through the broker.
|
|
- A second test OIDC client can log in through the same NuQloud issuer.
|
|
- Invalid redirect URIs and disabled clients are rejected.
|
|
|
|
### Phase 2: Admin UI
|
|
|
|
Outcome:
|
|
|
|
- Admin can manage private app clients from NuQloud.
|
|
|
|
Work:
|
|
|
|
- Add Identity Provider admin page.
|
|
- Add Nextcloud admin API bridge for clients and audit events. Started.
|
|
- Add create/edit/disable OIDC client actions. Started.
|
|
- Add redirect URI management.
|
|
- Add client secret generation and rotation.
|
|
- Add group access rules.
|
|
- Add setup snippets for common self-hosted apps.
|
|
- Add built-in setup guides for client templates. Completed.
|
|
- Ensure setup, start, recreate, and host-hybrid flows sync the identity provider as a built-in feature. Completed.
|
|
|
|
Exit criteria:
|
|
|
|
- Admin can register a private app without editing env files.
|
|
- Admin can disable access to a private app immediately.
|
|
|
|
### Phase 3: Service Access And Claims
|
|
|
|
Outcome:
|
|
|
|
- Different apps can receive different identity data.
|
|
|
|
Work:
|
|
|
|
- Add claim release policy per client.
|
|
- Add group claims.
|
|
- Add Powered Mode vs Full Qortal Mode claim behavior.
|
|
- Add optional consent screen for sensitive claims.
|
|
- Add service-level audit view.
|
|
|
|
Exit criteria:
|
|
|
|
- One app can receive only basic profile claims.
|
|
- Another approved app can receive Qortal-specific claims.
|
|
- Admin can inspect recent auth events.
|
|
|
|
### Phase 4: Logout, Revocation, And Session Management
|
|
|
|
Outcome:
|
|
|
|
- NuQloud can act as a stronger central identity layer.
|
|
|
|
Work:
|
|
|
|
- Add token revocation endpoint.
|
|
- Add refresh token support if needed.
|
|
- Add app session list.
|
|
- Add revoke all sessions for a user.
|
|
- Add logout redirect support.
|
|
- Investigate back-channel logout support for compatible clients.
|
|
|
|
Exit criteria:
|
|
|
|
- Admin or user can revoke app access.
|
|
- Tokens issued before revocation no longer work after their allowed window.
|
|
|
|
### Phase 5: App Templates And Reverse Proxy Auth
|
|
|
|
Outcome:
|
|
|
|
- NuQloud becomes easy to use as identity for a full private stack.
|
|
|
|
Work:
|
|
|
|
- Add templates for common apps.
|
|
- Add generated OIDC configuration instructions.
|
|
- Add optional reverse-proxy auth pattern for apps without OIDC.
|
|
- Add service catalog and app launcher hooks.
|
|
|
|
Exit criteria:
|
|
|
|
- Admin can add a common app from a template.
|
|
- Non-OIDC apps have a documented protected-proxy option.
|
|
|
|
## Security Requirements
|
|
|
|
- All public OIDC endpoints must validate inputs strictly.
|
|
- All internal admin APIs must require server-side auth.
|
|
- All state-changing Nextcloud controller routes must preserve CSRF protection
|
|
unless explicitly designed as token-authenticated API routes.
|
|
- No raw user input should be rendered into admin or user pages.
|
|
- Client secrets must never be logged or exposed after creation.
|
|
- Token signing keys must be rotatable.
|
|
- Redirect URIs must be exact-match allowlisted.
|
|
- Authorization codes must be single-use.
|
|
- Token claims must be scoped per client.
|
|
- Group and service access must be checked at authorization time.
|
|
- Audit logs must avoid storing sensitive token or secret material.
|
|
|
|
## Compatibility Risks
|
|
|
|
- Some self-hosted apps implement OIDC incompletely.
|
|
- Some apps require email to be present and verified.
|
|
- Some apps do not support group claims consistently.
|
|
- Logout behavior varies widely by client.
|
|
- Mobile apps may require app passwords or separate flows.
|
|
- Nextcloud version changes can affect the admin UI and `user_oidc` integration.
|
|
- Reverse proxy auth for non-OIDC apps has a larger blast radius and should be
|
|
treated as a separate hardening track.
|
|
|
|
## Open Questions
|
|
|
|
1. Should NuQloud support dynamic client registration, or only admin-created
|
|
clients?
|
|
2. Should refresh tokens be part of v1, or deferred until session management is
|
|
mature?
|
|
3. Should Qortal-specific claims be disabled by default in Powered Mode?
|
|
4. Should each client receive a pairwise `sub`, or should all clients receive
|
|
the same stable subject?
|
|
5. Should service access be based on Nextcloud groups, NuQloud-specific groups,
|
|
or both?
|
|
6. Should app templates live in the broker, the Nextcloud app, or static docs?
|
|
7. Should NuQloud provide an OIDC-aware reverse proxy profile, or only document
|
|
third-party proxy patterns?
|
|
|
|
## First MVP Target
|
|
|
|
The smallest useful MVP:
|
|
|
|
1. Keep Nextcloud login working through the broker.
|
|
2. Add one additional OIDC client manually in broker config or database.
|
|
3. Validate redirect URI and client secret.
|
|
4. Issue ID token and userinfo for that second client.
|
|
5. Gate access by an existing Nextcloud group.
|
|
6. Log successful and failed auth attempts.
|
|
|
|
Recommended first integration target:
|
|
|
|
- Gitea or OpenProject.
|
|
|
|
Both are realistic private-service examples and make the value of NuQloud as a
|
|
primary identity provider obvious.
|