Files
nextcloud-mcp-server/docs/oauth-architecture-comparison.md
T
Chris Coutinho f2af5a39a8 docs: Add ADR-004 - MCP Server as OAuth Client for Offline Access
- Supersedes ADR-002 which fundamentally misunderstood MCP protocol constraints
- Introduces "Sign-in with Nextcloud" architecture pattern
- MCP server becomes OAuth client to enable offline/background operations
- Implements full token rotation with reuse detection for security
- Includes comprehensive implementation details and migration strategy

Key architectural shift:
- From: Pass-through authentication (stateless, no offline access)
- To: MCP server as OAuth client (stateful, full offline capabilities)

The solution enables background workers to operate independently of MCP
sessions by storing and rotating refresh tokens securely.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 23:31:39 +01:00

13 KiB

OAuth Architecture Comparison: MCP Server Authentication Patterns

This document compares three authentication architectures for the MCP server, explaining the evolution from pass-through authentication to true offline access capabilities.

Pattern 1: Pass-Through Authentication (Current Implementation)

Architecture

┌─────────────┐     OAuth Flow    ┌─────────────┐
│  MCP Client │◄──────────────────│   OAuth     │
│   (Claude)  │                   │  Provider   │
└──────┬──────┘                   └─────────────┘
       │
       │ Access Token
       │ (per request)
       ▼
┌─────────────┐                   ┌─────────────┐
│ MCP Server  │───────────────────►│  Nextcloud  │
│(Pass-through)                   │    APIs     │
└─────────────┘                   └─────────────┘

Characteristics

Aspect Description
Token Flow MCP Client → MCP Server → Nextcloud
Token Storage None (tokens exist only during request)
Offline Access Impossible
Background Workers Not supported
User Consent Single OAuth flow (client-managed)
Complexity Low
Security High (no token persistence)

How It Works

  1. MCP Client performs OAuth with provider
  2. Client includes access token in each MCP request
  3. MCP Server validates token and forwards to Nextcloud
  4. Token discarded after request completes

Limitations

  • No operations possible without active MCP session
  • Background sync/indexing impossible
  • Cannot refresh tokens independently

Pattern 2: Token Exchange Delegation (ADR-002 - Flawed)

Architecture

┌─────────────┐                    ┌─────────────┐
│ MCP Client  │────────────────────│   OAuth     │
│  (Claude)   │                    │  Provider   │
└──────┬──────┘                    └──────┬──────┘
       │                                   │
       │ Access Token                      │ Service Account Token
       ▼                                   ▼
┌─────────────────────────────────────────────┐
│            MCP Server                        │
│  ┌────────────────────────────────────┐     │
│  │ Token Exchange (RFC 8693)          │     │
│  │ Subject: Service Account           │     │
│  │ Target: User                       │     │
│  └────────────────────────────────────┘     │
└───────────────┬─────────────────────────────┘
                │ Exchanged Token
                ▼
         ┌─────────────┐
         │  Nextcloud  │
         │    APIs     │
         └─────────────┘

Characteristics

Aspect Description
Token Flow Service Account → Exchange → User Token
Token Storage None (MCP server still stateless)
Offline Access Still impossible (circular dependency)
Background Workers Requires service account (rejected)
User Consent Implicit through service account
Complexity High
Security ⚠️ Service accounts violate OAuth principles

Why It Fails

  1. Circular Dependency: To exchange tokens, you need a token to exchange
  2. Service Account Problem: Creates Nextcloud user identity for service
  3. OAuth Violation: Service acts as itself, not on behalf of users
  4. No Bootstrap: Still can't obtain initial tokens offline

The Fatal Flaw

Q: How does background worker get tokens?
A: Use token exchange with service account

Q: How does service account get authorized?
A: Client credentials grant creates user account (violates OAuth)

Q: Can we use user's refresh token?
A: MCP server never sees refresh tokens (by design)

Pattern 3: MCP Server as OAuth Client (ADR-004 - Solution)

Architecture

        Layer 1: MCP Authentication          Layer 2: Nextcloud Authorization
┌─────────────┐                      ┌─────────────────┐                ┌─────────────┐
│ MCP Client  │                      │   MCP Server    │                │  Nextcloud  │
│  (Claude)   │                      │  (OAuth Client) │                │OAuth Provider
└──────┬──────┘                      └────────┬────────┘                └──────┬──────┘
       │                                      │                                │
       │ 1. MCP Request                       │ 2. Check stored tokens         │
       ├─────────────────────────────────────►│                                │
       │                                      │                                │
       │ 3. "Need Nextcloud Auth"             │                                │
       │◄─────────────────────────────────────┤                                │
       │                                      │                                │
       │ 4. User initiates OAuth              │ 5. OAuth Authorization         │
       ├─────────────────────────────────────►├───────────────────────────────►│
       │                                      │                                │
       │                                      │ 6. Access + Refresh Tokens     │
       │                                      │◄───────────────────────────────┤
       │                                      │                                │
       │                                      │ 7. Store encrypted tokens      │
       │                                      ├────────┐                       │
       │                                      │        ▼                       │
       │                                      │ ┌─────────────┐               │
       │                                      │ │Token Storage│               │
       │                                      │ └─────────────┘               │
       │ 8. "Auth Complete"                   │                                │
       │◄─────────────────────────────────────┤                                │
       │                                      │                                │
       │ 9. Subsequent requests               │ 10. Use stored tokens         │
       ├─────────────────────────────────────►├───────────────────────────────►│
       │                                      │                         Nextcloud APIs
       │                                      │                                │
       │                           Background │ 11. Refresh when expired       │
       │                              Worker──►├───────────────────────────────►│
       │                           (No client needed!)                         │

Characteristics

Aspect Description
Token Flow MCP Server owns Nextcloud tokens
Token Storage Encrypted refresh tokens
Offline Access Full support
Background Workers Use stored refresh tokens
User Consent Two OAuth flows (app + Nextcloud)
Complexity Medium-High
Security High (proper OAuth compliance)

How It Works

  1. Initial Setup:

    • User connects to MCP server (Layer 1 auth)
    • MCP server checks for stored Nextcloud tokens
    • If missing, triggers OAuth flow with Nextcloud
    • User authorizes MCP server to access Nextcloud
    • MCP server stores refresh token (encrypted)
  2. Subsequent Requests:

    • MCP server uses stored access token
    • Refreshes automatically when expired
    • No client involvement needed
  3. Background Operations:

    • Worker retrieves stored refresh token
    • Gets new access token from Nextcloud
    • Performs operations independently

Advantages

  • True offline access capability
  • OAuth-compliant with proper consent
  • Background workers can operate independently
  • Tokens persist across MCP sessions
  • Users can revoke access anytime

Trade-offs

  • Users must authorize twice (MCP + Nextcloud)
  • More complex token management
  • Requires secure token storage

Comparison Matrix

Feature Pass-Through Token Exchange MCP as OAuth Client
Offline Access No No Yes
Background Workers No No* Yes
Token Storage None None Refresh tokens
OAuth Compliance Full ⚠️ Violates Full
User Consent Once Implicit Twice
Implementation Complexity Low High Medium
Security High Medium High
Suitable For Interactive only N/A (flawed) Full platform

* Requires service accounts that violate OAuth principles


Evolution Summary

Stage 1: Simple Pass-Through

  • Goal: Basic MCP functionality
  • Result: Works well for interactive use
  • Limitation: No offline capabilities

Stage 2: Attempted Delegation

  • Goal: Enable offline access without changing architecture
  • Result: Circular dependencies, OAuth violations
  • Learning: MCP protocol constraints are fundamental

Stage 3: Application Pattern

  • Goal: True offline access with OAuth compliance
  • Result: MCP server as independent OAuth client
  • Trade-off: Additional complexity justified by requirements

Key Insights

  1. The MCP Protocol Boundary: The MCP protocol creates a fundamental boundary between client and server token management. Attempting to breach this boundary (ADR-002) leads to architectural contradictions.

  2. Service Accounts Don't Solve User Problems: Using service accounts for user operations violates OAuth's core principle of acting on behalf of users, not as a service identity.

  3. Double OAuth is Industry Standard: Major platforms (Zapier, IFTTT, Microsoft Power Automate) use this pattern - the integration platform is an OAuth client that maintains its own relationships with upstream services.

  4. Refresh Tokens Are The Solution: The OAuth spec designed refresh tokens specifically for offline access. Rejecting them (as ADR-002 did) means rejecting the standard solution.

  5. Complexity is Justified: The additional complexity of managing two OAuth flows is acceptable when offline access is a requirement. The alternative is no offline access at all.


Recommendations

For Simple Deployments

Use Pattern 1 (Pass-Through) if:

  • Offline access not needed
  • Only interactive operations required
  • Simplicity is priority

For Platform Deployments

Use Pattern 3 (MCP as OAuth Client) if:

  • Background sync/indexing required
  • Multiple users need service
  • Building integration platform
  • Offline operations critical

Never Use Pattern 2

Token Exchange with service accounts should not be used as it:

  • Doesn't enable true offline access
  • Violates OAuth principles
  • Adds complexity without solving the problem

References