Round-2 cleanup of PR #743 review comments not covered by d153e96:
- configuration.md: fix broken `#multi-user-oauth-modes` anchor; replace
with the two real anchors (Multi-User BasicAuth, Login Flow v2). Rewrite
the stale "always use OAuth2/OIDC with pre-configured clients" Best
Practices section to reflect the post-pivot mode matrix, and update the
Docker volume example to mount the encrypted app-password store
(`TOKEN_STORAGE_DB`) rather than obsolete `.oauth` client storage.
- semantic-search-architecture.md: rename remaining body references from
the deprecated `VECTOR_SYNC_ENABLED` to `ENABLE_SEMANTIC_SEARCH` so the
doc matches configuration.md / troubleshooting.md.
- running.md: relabel "OAuth Mode (Recommended)" as
"Login Flow v2 / OAuth issuer mode (--oauth)", drop the misleading
"(Legacy)" suffix from BasicAuth, drop the
`NEXTCLOUD_OIDC_CLIENT_ID/SECRET` example (tied to the retired
direct-OAuth-to-Nextcloud flow), and add a note explaining what
`--oauth` actually enables post-pivot.
- keycloak-multi-client-validation.md, oauth-impersonation-findings.md:
add a deprecation banner pointing at ADR-022 / Login Flow v2. Files
retained because ADR-002 and CLAUDE.md still cite them.
- auth-flows.md: clarify under the Astrolabe → MCP diagram that the
Nextcloud-OIDC JWKS path applies to Multi-User BasicAuth; under
Login Flow v2 the MCP server validates tokens against its own JWKS.
- login-flow-v2.md: clarify the sticky-session note — affinity must key
on the OAuth bearer token (or user-bound cookie), not source IP, since
MCP clients may not maintain stable IPs across the provisioning flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
13 KiB
Authentication Flows by Deployment Mode
This document provides a unified reference for the auth flows in each supported deployment mode. For configuration details, see Authentication. For Login Flow v2 architecture and setup, see Login Flow v2.
Quick Reference Matrix
| Mode | Client → MCP → NC | Background Sync | Astrolabe → MCP |
|---|---|---|---|
| Single-User BasicAuth | Embedded credentials | Same credentials | N/A |
| Multi-User BasicAuth | Header pass-through | Stored app password (optional) | OAuth Bearer token |
| Login Flow v2 | OAuth → MCP, app pwd → NC | Stored app password | OAuth Bearer token |
Communication Patterns
This document covers three distinct communication patterns:
- MCP Client → MCP Server → Nextcloud: Interactive tool calls initiated by users through MCP clients (Claude Desktop, claude.ai, custom clients).
- MCP Server → Nextcloud: Background operations like vector sync that run without user interaction.
- Astrolabe → MCP Server: Astrolabe app backend communication for settings UI and unified search.
Deployment Modes
1. Single-User BasicAuth
Use Case: Personal Nextcloud instance, local development, single-user deployments.
MCP Client → MCP Server → Nextcloud
MCP Client MCP Server Nextcloud
│ │ │
│── MCP Request ─────────────▶│ │
│ (no auth required) │ │
│ │── HTTP + BasicAuth ───────▶│
│ │ Authorization: Basic │
│ │ (embedded credentials) │
│ │◀── API Response ───────────│
│◀── Tool Result ─────────────│ │
Key characteristics:
- Credentials embedded in server configuration (
NEXTCLOUD_USERNAME,NEXTCLOUD_PASSWORD) - Single shared
NextcloudClientcreated at startup - No MCP-level authentication required (server trusts local clients)
- All requests use the same Nextcloud user
Implementation: context.py — returns the shared client from lifespan context
Background Sync
Uses the same embedded credentials as interactive requests. The background job accesses Nextcloud with the configured username/password.
Astrolabe Integration
Not applicable — Astrolabe is only used in multi-user deployments where users need personal settings and per-user state.
2. Multi-User BasicAuth
Use Case: Internal deployment where users provide their own Nextcloud credentials via HTTP headers.
MCP Client → MCP Server → Nextcloud
MCP Client MCP Server Nextcloud
│ │ │
│── MCP Request ─────────────▶│ │
│ Authorization: Basic │ │
│ (user credentials) │ │
│ │── BasicAuthMiddleware ────▶│
│ │ Extracts credentials │
│ │ │
│ │── HTTP + BasicAuth ───────▶│
│ │ (pass-through) │
│ │◀── API Response ───────────│
│◀── Tool Result ─────────────│ │
Key characteristics:
BasicAuthMiddlewareextracts credentials from theAuthorization: Basicheader- Credentials passed through to Nextcloud (not stored)
- Client created per-request from extracted credentials
- Stateless — no credential storage between requests
Background Sync (Optional)
If users provision an app password (via Astrolabe or nc_auth_provision_access), the server can run background jobs on their behalf:
Astrolabe MCP Server Nextcloud
│ │ │
│── Store app password ──────▶│ │
│ (via management API) │ │
│ │ [Encrypt + persist locally]│
│ │ (SQLite, Fernet) │
│◀── Confirmation ────────────│ │
│ │ │
│ [Background job] │ │
│ │── Retrieve app password ──▶│
│ │── HTTP + BasicAuth ───────▶│
│ │◀── API Response ───────────│
Requirements: TOKEN_ENCRYPTION_KEY, TOKEN_STORAGE_DB.
Astrolabe → MCP Server
Astrolabe MCP Server Nextcloud OIDC
│ │ │
│── OAuth Flow ──────────────▶│◀── Token from IdP ────────▶│
│ (user initiates) │ │
│ │ │
│── Bearer Token ────────────▶│ │
│ (management API calls) │ │
│ │── Validate via JWKS ──────▶│
│ │ (or introspection) │
│◀── API Response ────────────│ │
Key characteristics:
- Astrolabe has its own OAuth client registered in Nextcloud
- Tokens are validated by the MCP server using Nextcloud OIDC JWKS
- Authorization check:
token.sub == requested_resource_owner
Note: The diagram and JWKS source above apply to Multi-User BasicAuth, where Nextcloud is the IdP. Under Login Flow v2 the MCP server is its own OAuth issuer and validates Bearer tokens against its own JWKS (or via local introspection of opaque tokens) — Nextcloud's JWKS is not involved on the MCP-client → MCP-server leg. See the Login Flow v2 section below.
3. Login Flow v2
Use Case: Hosted multi-user deployments, OAuth-based MCP clients (claude.ai, Astrolabe Cloud), production. Recommended for any setup where MCP clients shouldn't handle Nextcloud credentials directly.
This mode replaces the previously-supported "OAuth Single-Audience" and "OAuth Token Exchange" modes, both of which required upstream Nextcloud patches that were never merged. See ADR-022 for the rationale.
MCP Client → MCP Server → Nextcloud (steady state)
MCP Client MCP Server Nextcloud
│ │ │
│── Bearer Token ────────────▶│ │
│ (issued by MCP server, │ │
│ mcp:* scopes) │ │
│ │── Validate scopes ─────────│
│ │ (@require_scopes) │
│ │ │
│ │── Lookup user's │
│ │ stored app password │
│ │ │
│ │── HTTP + BasicAuth ───────▶│
│ │ Authorization: Basic │
│ │ (per-user app password) │
│ │◀── API Response ───────────│
│◀── Tool Result ─────────────│ │
Key characteristics:
- MCP client authenticates to MCP server via OAuth 2.1 + PKCE
- MCP server is the OAuth authorization server (DCR via RFC 7591)
mcp:*scopes (e.g.mcp:notes.read,mcp:notes.write) gate tool access- Per-user app password obtained via Login Flow v2 and stored encrypted in SQLite
- App passwords appear in Nextcloud's Settings → Security → Devices & Sessions and are user-revocable
First-Use Provisioning (one-time per user)
MCP Client MCP Server Nextcloud
│ │ │
│── Bearer Token + request ──▶│ │
│ │ No stored app password │
│ │ │
│◀── Elicit URL or 401 ───────│ │
│ "Visit <login-url>" │ │
│ │── POST /index.php/login/v2▶│
│ │◀── login_url, poll_token ──│
│ │ │
│ User opens login_url in browser, authenticates, "Grant"│
│ ──────────────────────────────────────────────────────▶│
│ │ │
│ │── Poll endpoint (bg) ─────▶│
│ │◀── loginName, appPassword ─│
│ │ │
│ │── Encrypt + store │
│ │ in tokens.db │
│ │ │
│── Retry request ───────────▶│── Basic Auth as above ────▶│
Background Sync
Uses the same per-user app password retrieved from encrypted storage. No token refresh needed — Nextcloud app passwords don't expire (until the user revokes them).
MCP Server Nextcloud
│ │
[Background job starts] │ │
│── Retrieve app password ──▶│
│ (per user, from SQLite) │
│ │
│── HTTP + BasicAuth ───────▶│
│◀── API Response ───────────│
Astrolabe → MCP Server
Same as Multi-User BasicAuth — see Astrolabe → MCP Server above.
Configuration Quick Reference
Single-User BasicAuth
NEXTCLOUD_HOST=https://nextcloud.example.com
NEXTCLOUD_USERNAME=admin
NEXTCLOUD_PASSWORD=<app-password>
Multi-User BasicAuth
NEXTCLOUD_HOST=https://nextcloud.example.com
ENABLE_MULTI_USER_BASIC_AUTH=true
# Optional: app-password storage for background sync
TOKEN_ENCRYPTION_KEY=<fernet-key>
TOKEN_STORAGE_DB=/app/data/tokens.db
Login Flow v2
NEXTCLOUD_HOST=https://nextcloud.example.com
ENABLE_LOGIN_FLOW=true
# Required for app-password storage
TOKEN_ENCRYPTION_KEY=<fernet-key>
TOKEN_STORAGE_DB=/app/data/tokens.db
# Public URLs (for browser redirects)
NEXTCLOUD_MCP_SERVER_URL=https://mcp.example.com
NEXTCLOUD_PUBLIC_ISSUER_URL=https://nextcloud.example.com
See Login Flow v2 for full setup, scope reference, and troubleshooting.
Related Documentation
- Authentication — mode comparison and selection
- Login Flow v2 — multi-user setup details
- Configuration — environment variable reference
- ADR-022 — design rationale for mode consolidation