docs: correct OIDC architecture framing for Login Flow v2

The previous round of review feedback rested on a misunderstanding —
that the MCP server is "the OAuth issuer" under Login Flow v2 and that
NEXTCLOUD_OIDC_CLIENT_ID/SECRET are external-IdP-only. Code says
otherwise (app.py:619/625/703-717, unified_verifier.py:72):

- The MCP server is an OIDC relying party of Nextcloud OIDC. Tokens are
  signed by Nextcloud and validated against Nextcloud's JWKS in all
  modes — the server has no private signing keys.
- Static NEXTCLOUD_OIDC_CLIENT_ID/SECRET are the preferred way to
  register the MCP server as that relying party; RFC 7591 DCR is a
  fallback when both are unset.
- Login Flow v2 layers per-user app-password acquisition on top — it
  governs the MCP→Nextcloud data leg, not the relying-party setup.

This commit reverts the inaccuracies introduced by 35c115e and reframes
the original `login-flow-v2.md` to match what the code does:

- login-flow-v2.md: revise "How It Works" to describe the MCP server
  as an OIDC RP + OAuth facade (not a standalone issuer); rename
  "OAuth Issuer Endpoints" → "OAuth Endpoints" with a note that those
  endpoints front Nextcloud OIDC; add NEXTCLOUD_OIDC_CLIENT_ID/SECRET
  to the required env vars with DCR documented as fallback.
- running.md: restore the static-creds Docker example (deleted in
  35c115e on the wrong reasoning that it was tied to the retired
  direct-OAuth-to-Nextcloud flow); rewrite the OAuth Mode section
  intro to describe the actual relying-party + facade architecture.
- configuration.md: fix Best Practices "For Production" to mention
  static creds as preferred / DCR as fallback; restore the .oauth
  Docker volume alongside data so DCR-registered MCP-client state and
  the encrypted app-password DB both persist.
- auth-flows.md: drop the note added in 35c115e that wrongly claimed
  the MCP server validates Bearer tokens against its own JWKS under
  Login Flow v2 — it validates against Nextcloud's JWKS in all modes;
  reword the Login Flow v2 "Key characteristics" bullet that called
  the MCP server "the OAuth authorization server".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-04-30 02:29:01 +02:00
co-authored by Claude Opus 4.7
parent 35c115ead6
commit 319e82774e
4 changed files with 52 additions and 27 deletions
+2 -3
View File
@@ -125,8 +125,7 @@ Astrolabe MCP Server Nextcloud OIDC
- 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](#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.
- The same JWKS-based validation path applies under [Login Flow v2](#3-login-flow-v2) — the MCP server is an OIDC relying party of Nextcloud OIDC in both modes; Login Flow v2 only changes the MCP→Nextcloud credential leg (per-user app passwords).
---
@@ -159,7 +158,7 @@ MCP Client MCP Server Nextcloud
**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 server is an **OIDC relying party of Nextcloud OIDC** + an OAuth facade for MCP clients (RFC 7591 DCR for MCP-client registration; the server's own RP credentials come from `NEXTCLOUD_OIDC_CLIENT_ID/SECRET`, with DCR fallback). Tokens are signed by Nextcloud OIDC and validated against Nextcloud's JWKS.
- `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