Files
mcp-nextcloud/docs/auth-flows.md
T
Chris CoutinhoandClaude Opus 4.7 282c245da1 refactor(config)!: drop ENABLE_MULTI_USER_BASIC_AUTH env var, fail loud on legacy aliases
Same pattern as the ENABLE_LOGIN_FLOW removal in the previous commit:
the deployment mode (MCP_DEPLOYMENT_MODE) is the single source of truth
for selecting an auth flow. The ENABLE_MULTI_USER_BASIC_AUTH env-var
alias is redundant with `MCP_DEPLOYMENT_MODE=multi_user_basic`.

Unlike the ENABLE_LOGIN_FLOW removal — where silent removal was safe
because Login Flow v2 is the auto-detection default — silent removal
here would be a surprise: a user with only ENABLE_MULTI_USER_BASIC_AUTH=true
in their .env would auto-detect into LOGIN_FLOW after upgrade (wrong
runtime mode). Mitigation: detect_auth_mode now reads os.environ
directly for both legacy aliases and raises ValueError with a one-line
migration message if either is set. Applied retroactively to
ENABLE_LOGIN_FLOW as well — loud is better than silent.

- nextcloud_mcp_server/config.py:
  - Drop the dynaconf env-var alias entry for ENABLE_MULTI_USER_BASIC_AUTH.
  - Update the `enable_multi_user_basic_auth` field docstring to mark it
    as derived / not user-settable.
  - `_is_multi_user_mode()` (early-config helper, runs before Settings
    is built) switched to checking MCP_DEPLOYMENT_MODE directly. Now
    consistent with the canonical detection in detect_auth_mode.
- nextcloud_mcp_server/config_validators.py:
  - Drop the auto-detection branch (`if settings.enable_multi_user_basic_auth`).
    Selection of MULTI_USER_BASIC is now exclusively via the explicit
    MCP_DEPLOYMENT_MODE branch.
  - Add `enable_multi_user_basic_auth` to `_sync_derived_flags` alongside
    `enable_login_flow` — both flags are now derived from the resolved mode.
  - Drop `enable_multi_user_basic_auth` from
    `MODE_REQUIREMENTS[MULTI_USER_BASIC].required` and from the
    `forbidden` lists of SINGLE_USER_BASIC and LOGIN_FLOW (no longer
    user input → no meaningful forbidden check).
  - Add loud-deprecation `ValueError` block at the top of detect_auth_mode
    that errors with a clear migration message when ENABLE_MULTI_USER_BASIC_AUTH
    or ENABLE_LOGIN_FLOW is found in os.environ.
- tests/unit/test_config_validators.py:
  - Switch ~10 fixtures from `enable_multi_user_basic_auth=True` to
    `deployment_mode="multi_user_basic"` (mirrors `enable_login_flow`
    treatment from the previous commit).
  - Switch two `patch.dict(os.environ, {"ENABLE_MULTI_USER_BASIC_AUTH": "true"})`
    blocks to use MCP_DEPLOYMENT_MODE.
  - Rename `test_forbidden_multi_user_basic_auth` to
    `test_forbidden_multi_user_basic_when_credentials_present` — the
    scenario is now an explicit-mode + credentials conflict, not an
    env-var-flag conflict.
  - Add `test_legacy_enable_multi_user_basic_auth_env_var_errors` and
    `test_legacy_enable_login_flow_env_var_errors` to exercise the new
    loud-deprecation ValueError path.
- docker-compose.yml: mcp-multi-user-basic profile switched to
  `MCP_DEPLOYMENT_MODE=multi_user_basic`.
- env.sample: replaced `#ENABLE_MULTI_USER_BASIC_AUTH=true` example with
  `#MCP_DEPLOYMENT_MODE=multi_user_basic`.
- docs/authentication.md, configuration.md, troubleshooting.md,
  auth-flows.md, webhook-management-guide.md,
  configuration-migration-v2.md, ADR-025: replaced env-var examples
  with the canonical MCP_DEPLOYMENT_MODE form.
- docs/ADR-020: marked partly superseded by ADR-022.
- CLAUDE.md: Multi-User BasicAuth section updated to set
  MCP_DEPLOYMENT_MODE.
- nextcloud_mcp_server/vector/oauth_sync.py: module docstring updated.

BREAKING CHANGE: ENABLE_MULTI_USER_BASIC_AUTH is no longer read from
the environment, and setting it now raises a startup ValueError with
a migration message. Replace `ENABLE_MULTI_USER_BASIC_AUTH=true` with
`MCP_DEPLOYMENT_MODE=multi_user_basic`. The same loud-deprecation
check is also applied to the recently-removed ENABLE_LOGIN_FLOW —
replace with `MCP_DEPLOYMENT_MODE=login_flow` (or drop both;
`login_flow` is the auto-detect default when no other auth env vars
are set).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 20:06:16 +02:00

255 lines
13 KiB
Markdown

# 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](authentication.md). For Login Flow v2 architecture and setup, see [Login Flow v2](login-flow-v2.md).
## Quick Reference Matrix
| Mode | Client → MCP → NC | Background Sync | Astrolabe (hosted UI) → MCP |
|------|-------------------|-----------------|------------------------------|
| [Single-User BasicAuth](#1-single-user-basicauth) | Embedded credentials | Same credentials | N/A |
| [Multi-User BasicAuth](#2-multi-user-basicauth) | Header pass-through | Stored app password (optional) | OAuth Bearer token |
| [Login Flow v2](#3-login-flow-v2) | OAuth → MCP, app pwd → NC | Stored app password | OAuth Bearer token |
## Communication Patterns
This document covers three distinct communication patterns:
1. **MCP Client → MCP Server → Nextcloud**: Interactive tool calls initiated by users through MCP clients (Claude Desktop, claude.ai, custom clients).
2. **MCP Server → Nextcloud**: Background operations like vector sync that run without user interaction.
3. **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 `NextcloudClient` created 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:**
- `BasicAuthMiddleware` extracts credentials from the `Authorization: Basic` header
- 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 OIDC Provider
│ │ │
│── 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 with the IdP (Nextcloud OIDC by default; Keycloak / Cognito / etc. when configured via `OIDC_DISCOVERY_URL`)
- Tokens are validated by the MCP server using the IdP's JWKS (Nextcloud OIDC's JWKS by default; whichever IdP is configured otherwise)
- Authorization check: `token.sub == requested_resource_owner`
- The same JWKS-based validation path applies under [Login Flow v2](#3-login-flow-v2) — the MCP server is an OIDC relying party of the configured IdP in both modes; Login Flow v2 only changes the MCP→Nextcloud credential leg (per-user app passwords).
---
### 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](ADR-022-deployment-mode-consolidation.md) for the rationale.
#### MCP Client → MCP Server → Nextcloud (steady state)
```
MCP Client MCP Server Nextcloud
│ │ │
│── Bearer Token ────────────▶│ │
│ (issued by configured IdP,│ │
│ per-app 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 an **OIDC relying party of a configurable IdP** (Nextcloud OIDC by default; Keycloak, AWS Cognito, etc. via `OIDC_DISCOVERY_URL`) + an OAuth facade for MCP clients. RFC 7591 DCR is used to register the MCP-client side; the server's own RP credentials come from `NEXTCLOUD_OIDC_CLIENT_ID/SECRET` (generic OIDC creds), with DCR fallback. Tokens are signed by the chosen IdP and validated against that IdP's JWKS.
- Per-app scopes (e.g. `notes.read`, `talk.read`, `files.write`) gate tool access — see [Login Flow v2 → Scope Reference](login-flow-v2.md#scope-reference) for the full list
- Per-user app password obtained via Login Flow v2 (Nextcloud-specific protocol, used regardless of which IdP authenticated the client) 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](#astrolabe--mcp-server) above.
---
## Configuration Quick Reference
### Single-User BasicAuth
```bash
NEXTCLOUD_HOST=https://nextcloud.example.com
NEXTCLOUD_USERNAME=admin
NEXTCLOUD_PASSWORD=<app-password>
```
### Multi-User BasicAuth
```bash
NEXTCLOUD_HOST=https://nextcloud.example.com
MCP_DEPLOYMENT_MODE=multi_user_basic
# Optional: app-password storage for background sync
TOKEN_ENCRYPTION_KEY=<fernet-key>
TOKEN_STORAGE_DB=/app/data/tokens.db
```
### Login Flow v2
```bash
NEXTCLOUD_HOST=https://nextcloud.example.com
MCP_DEPLOYMENT_MODE=login_flow
# 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](login-flow-v2.md) for full setup, scope reference, and troubleshooting.
---
## Related Documentation
- [Authentication](authentication.md) — mode comparison and selection
- [Login Flow v2](login-flow-v2.md) — multi-user setup details
- [Configuration](configuration.md) — environment variable reference
- [ADR-022](ADR-022-deployment-mode-consolidation.md) — design rationale for mode consolidation