From 35c115ead6c368a98434d7068496dfb5dc9264e4 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Thu, 30 Apr 2026 01:57:16 +0200 Subject: [PATCH] docs: address remaining Login Flow v2 review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- docs/auth-flows.md | 2 ++ docs/configuration.md | 25 +++++++++++++++--------- docs/keycloak-multi-client-validation.md | 3 +++ docs/login-flow-v2.md | 2 ++ docs/oauth-impersonation-findings.md | 3 +++ docs/running.md | 24 +++++++++++------------ docs/semantic-search-architecture.md | 20 +++++++++---------- 7 files changed, 47 insertions(+), 32 deletions(-) diff --git a/docs/auth-flows.md b/docs/auth-flows.md index 28eaeef0..ff74c53e 100644 --- a/docs/auth-flows.md +++ b/docs/auth-flows.md @@ -126,6 +126,8 @@ Astrolabe MCP Server Nextcloud OIDC - 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](#3-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 diff --git a/docs/configuration.md b/docs/configuration.md index f57bfa2c..55df25de 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -24,7 +24,8 @@ cp env.sample .env # Full reference with all options Then choose your deployment mode: - [Single-User BasicAuth](#single-user-basicauth-mode) - Simplest for personal instances -- [Multi-User OAuth](#multi-user-oauth-modes) - Recommended for production +- [Multi-User BasicAuth](#multi-user-basicauth-mode) - Internal deployments with credential pass-through +- [Login Flow v2](#login-flow-v2-mode) - Recommended for hosted / OAuth-based MCP clients - [Deployment Mode Selection](#deployment-mode-selection) - Explicit mode declaration --- @@ -627,27 +628,33 @@ uv run nextcloud-mcp-server --no-oauth \ ### For Development -- Use BasicAuth for quick setup and testing -- Or use OAuth with auto-registration (dynamic client registration) +- Use Single-User BasicAuth for the fastest local setup (one user, one app password) - Store `.env` file in your project directory - Add `.env` to `.gitignore` ### For Production -- **Always use OAuth2/OIDC** with pre-configured clients -- Store OAuth client credentials securely +Pick the mode that matches your deployment topology — there is no single "always" answer: + +- **Multi-user / hosted** — use [Login Flow v2](login-flow-v2.md). MCP clients authenticate via OAuth 2.1 + DCR (no pre-configured client to manage); per-user Nextcloud access is stored as encrypted app passwords. +- **Internal multi-user** — Multi-User BasicAuth pass-through (clients send `Authorization: Basic` headers) is fully supported when users manage their own Nextcloud credentials. +- **Personal / self-hosted** — Single-User BasicAuth with a Nextcloud app password is the simplest production setup. + +In all modes: + - Use environment variables from your deployment platform (Docker secrets, Kubernetes ConfigMaps, etc.) - Never commit credentials to version control - SQLite database permissions are handled automatically by the server ### For Docker -- Mount OAuth client storage as a volume for persistence: +- Under Login Flow v2, mount the encrypted app-password store as a volume so per-user provisioning survives container restarts: ```bash - docker run -v $(pwd)/.oauth:/app/.oauth --env-file .env \ - ghcr.io/cbcoutinho/nextcloud-mcp-server:latest + docker run -v $(pwd)/data:/app/data --env-file .env \ + ghcr.io/cbcoutinho/nextcloud-mcp-server:latest --oauth ``` -- Use Docker secrets for sensitive values in production + (`TOKEN_STORAGE_DB=/app/data/tokens.db` in `.env`.) +- Use Docker secrets for sensitive values in production (`TOKEN_ENCRYPTION_KEY`, `NEXTCLOUD_PASSWORD`, etc.) --- diff --git a/docs/keycloak-multi-client-validation.md b/docs/keycloak-multi-client-validation.md index c9b8a964..0e1285fe 100644 --- a/docs/keycloak-multi-client-validation.md +++ b/docs/keycloak-multi-client-validation.md @@ -1,5 +1,8 @@ # Keycloak Multi-Client Token Validation +> [!WARNING] +> **Deprecated — historical reference only.** This document describes the direct-OAuth-to-Nextcloud architecture that was retired in favor of Login Flow v2. See [ADR-022](ADR-022-deployment-mode-consolidation.md) and [Login Flow v2](login-flow-v2.md) for the current approach. Retained because [ADR-002](ADR-002-vector-sync-authentication.md) and `CLAUDE.md` still cite this investigation for context. + ## Executive Summary **Question**: Can Nextcloud's `user_oidc` app (configured with client A) validate bearer tokens from client B in the same Keycloak realm? diff --git a/docs/login-flow-v2.md b/docs/login-flow-v2.md index 902c8acb..47124667 100644 --- a/docs/login-flow-v2.md +++ b/docs/login-flow-v2.md @@ -242,6 +242,8 @@ The user revoked it from **Settings → Security → Devices & Sessions**. Delet The provisioning session store is in-memory; `ENABLE_LOGIN_FLOW=true` assumes a single worker. Running with `uvicorn --workers N` will cause provisioning sessions to randomly fail. For higher concurrency, scale horizontally (multiple containers behind a sticky-session load balancer) rather than within a single process. +> **Sticky-session keying:** route on the user's OAuth bearer token (or a session cookie tied to the user) — **not** on source IP. MCP clients may not maintain stable IPs between the request that initiates provisioning and the polling request that completes it, so IP-based affinity will silently break the flow. A stable per-user identifier from the `Authorization` header is the right key. + ## See Also - [ADR-022: Deployment Mode Consolidation](ADR-022-deployment-mode-consolidation.md) — design rationale diff --git a/docs/oauth-impersonation-findings.md b/docs/oauth-impersonation-findings.md index 0421c14c..cdf3dabd 100644 --- a/docs/oauth-impersonation-findings.md +++ b/docs/oauth-impersonation-findings.md @@ -1,5 +1,8 @@ # OAuth Impersonation Investigation Findings +> [!WARNING] +> **Deprecated — historical reference only.** This document describes the direct-OAuth-to-Nextcloud / token-exchange architecture that was retired in favor of Login Flow v2. See [ADR-022](ADR-022-deployment-mode-consolidation.md) and [Login Flow v2](login-flow-v2.md) for the current approach. Retained because [ADR-002](ADR-002-vector-sync-authentication.md) still cites this investigation for context. + **Date**: 2025-11-02 **Last Updated**: 2025-11-02 (Token Exchange Resolution) **Status**: Implementation Complete - Token Exchange Working diff --git a/docs/running.md b/docs/running.md index e68d6630..be5016db 100644 --- a/docs/running.md +++ b/docs/running.md @@ -17,15 +17,17 @@ Before running the server: Start the server using Docker: ```bash -# OAuth mode (recommended) +# Login Flow v2 / OAuth issuer mode (--oauth, recommended for multi-user) docker run -p 127.0.0.1:8000:8000 --env-file .env --rm \ ghcr.io/cbcoutinho/nextcloud-mcp-server:latest --oauth -# BasicAuth mode +# BasicAuth mode (single-user or multi-user pass-through) docker run -p 127.0.0.1:8000:8000 --env-file .env --rm \ ghcr.io/cbcoutinho/nextcloud-mcp-server:latest ``` +> **Note:** The `--oauth` flag turns on the OAuth-issuer layer used by [Login Flow v2](login-flow-v2.md), the recommended multi-user mode. It does **not** forward client OAuth tokens to Nextcloud — Nextcloud is always reached via per-user app passwords (Login Flow v2) or Basic Auth credentials. + The server will start on `http://127.0.0.1:8000` by default. --- @@ -34,30 +36,26 @@ The server will start on `http://127.0.0.1:8000` by default. ### Basic Docker Run -#### OAuth Mode (Recommended) +#### Login Flow v2 / OAuth issuer mode (`--oauth`) + +Recommended for multi-user deployments. The MCP server acts as the OAuth issuer for MCP clients; per-user Nextcloud access is obtained via [Login Flow v2](login-flow-v2.md) and stored as encrypted app passwords. ```bash -# OAuth with auto-registration +# OAuth issuer with DCR (Dynamic Client Registration) docker run -p 127.0.0.1:8000:8000 --env-file .env --rm \ ghcr.io/cbcoutinho/nextcloud-mcp-server:latest --oauth -# OAuth with custom port +# OAuth issuer on a custom port docker run -p 127.0.0.1:8080:8000 --env-file .env --rm \ ghcr.io/cbcoutinho/nextcloud-mcp-server:latest --oauth -# OAuth with pre-configured client -docker run -p 127.0.0.1:8000:8000 --env-file .env --rm \ - -e NEXTCLOUD_OIDC_CLIENT_ID=abc123 \ - -e NEXTCLOUD_OIDC_CLIENT_SECRET=xyz789 \ - ghcr.io/cbcoutinho/nextcloud-mcp-server:latest --oauth - -# OAuth with specific apps only +# OAuth issuer with specific apps only docker run -p 127.0.0.1:8000:8000 --env-file .env --rm \ ghcr.io/cbcoutinho/nextcloud-mcp-server:latest --oauth \ --enable-app notes --enable-app calendar ``` -#### BasicAuth Mode (Legacy) +#### BasicAuth Mode ```bash # BasicAuth (requires NEXTCLOUD_USERNAME/PASSWORD in .env) diff --git a/docs/semantic-search-architecture.md b/docs/semantic-search-architecture.md index 87776bd5..025a538d 100644 --- a/docs/semantic-search-architecture.md +++ b/docs/semantic-search-architecture.md @@ -86,7 +86,7 @@ graph TB ## How It Works: Background Synchronization -Background synchronization runs automatically when `VECTOR_SYNC_ENABLED=true`, discovering changes and indexing documents without user intervention. +Background synchronization runs automatically when `ENABLE_SEMANTIC_SEARCH=true`, discovering changes and indexing documents without user intervention. ```mermaid sequenceDiagram @@ -478,7 +478,7 @@ except Exception as e: **BasicAuth:** - Set `NEXTCLOUD_USERNAME` and `NEXTCLOUD_PASSWORD` -- Background sync works immediately when `VECTOR_SYNC_ENABLED=true` +- Background sync works immediately when `ENABLE_SEMANTIC_SEARCH=true` - Credentials stored in `.env` file (secure server access required) **OAuth:** @@ -497,7 +497,7 @@ except Exception as e: **In-Memory Mode:** ```bash -VECTOR_SYNC_ENABLED=true +ENABLE_SEMANTIC_SEARCH=true # QDRANT_LOCATION not set → defaults to :memory: ``` - Fastest startup @@ -506,7 +506,7 @@ VECTOR_SYNC_ENABLED=true **Persistent Local Mode:** ```bash -VECTOR_SYNC_ENABLED=true +ENABLE_SEMANTIC_SEARCH=true QDRANT_LOCATION=/var/lib/qdrant ``` - Vectors survive restarts @@ -515,7 +515,7 @@ QDRANT_LOCATION=/var/lib/qdrant **Network Mode (Recommended for Production):** ```bash -VECTOR_SYNC_ENABLED=true +ENABLE_SEMANTIC_SEARCH=true QDRANT_URL=http://qdrant:6333 QDRANT_API_KEY=secret # optional ``` @@ -563,12 +563,12 @@ OLLAMA_EMBEDDING_MODEL=nomic-embed-text # 768-dimensional vectors **Enable Semantic Search:** ```bash -VECTOR_SYNC_ENABLED=true # Default: false (opt-in) +ENABLE_SEMANTIC_SEARCH=true # Default: false (opt-in) ``` **Qdrant Vector Database:** ```bash -# In-memory mode (default if VECTOR_SYNC_ENABLED=true) +# In-memory mode (default if ENABLE_SEMANTIC_SEARCH=true) # QDRANT_LOCATION not set → uses :memory: # Persistent local mode @@ -617,7 +617,7 @@ VECTOR_SYNC_INTERVAL=3600 # Scan interval in seconds (default: 1 hour) ## Operational Behavior -### What Happens When VECTOR_SYNC_ENABLED=true +### What Happens When ENABLE_SEMANTIC_SEARCH=true **Immediate (Server Startup):** 1. MCP server connects to Qdrant (creates collection if needed) @@ -752,7 +752,7 @@ For detailed observability setup, see [docs/observability.md](observability.md). **Diagnosis Flow:** 1. Check sync status: `nc_get_vector_sync_status` - - `sync_enabled: false` → Enable with `VECTOR_SYNC_ENABLED=true` + - `sync_enabled: false` → Enable with `ENABLE_SEMANTIC_SEARCH=true` - `status: error` → Check scanner logs for failures 2. Check queue size: - `pending_documents > 0` → Processing in progress, wait @@ -765,7 +765,7 @@ For detailed observability setup, see [docs/observability.md](observability.md). - Model not found → Pull model: `ollama pull nomic-embed-text` **Common Causes:** -- Sync disabled (default): Enable `VECTOR_SYNC_ENABLED=true` +- Sync disabled (default): Enable `ENABLE_SEMANTIC_SEARCH=true` - Ollama not running: Start Ollama service - Qdrant not accessible: Check network/URL - First scan in progress: Wait up to 1 hour + processing time