You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: Reject service account tokens as OAuth authentication pattern
Service account tokens (client_credentials grant) violate OAuth "act on-behalf-of"
principles and have been moved to ADR-002's "Will Not Implement" section.
## Problem Discovery
Testing revealed that service account tokens create Nextcloud user accounts
(e.g., `service-account-nextcloud-mcp-server`) due to user_oidc's bearer
provisioning feature. This violates core OAuth principles:
- ❌ Creates stateful server identity in Nextcloud
- ❌ All actions attributed to service account, not real user
- ❌ Breaks audit trail and user attribution
- ❌ Service account becomes "admin by another name"
## Changes
### Documentation (ADR-002)
- Moved service account (old Tier 1) to "Will Not Implement" section
- Added "OAuth Act On-Behalf-Of Principle" section
- Renumbered tiers:
- Tier 1: Impersonation (NOT IMPLEMENTED)
- Tier 2: Delegation via token exchange (IMPLEMENTED)
- Updated status to reflect rejection of service accounts
### Code Warnings
- Added comprehensive warning to KeycloakOAuthClient.get_service_account_token()
- Clarified VALID use: only as subject_token for RFC 8693 token exchange
- Clarified INVALID use: direct API access with service account token
### Supporting Documentation
- CLAUDE.md: Removed outdated "Tier 1" references, added rejection note
- oauth-impersonation-findings.md: Added prominent update banner
- audience-validation-setup.md: Updated tier numbers, added rejection note
- tests/manual/test_token_exchange.py: Added warning comment
## Valid Patterns (ADR-002)
✅ Foreground operations: User's access token from MCP request
✅ Background operations: Token exchange (impersonation/delegation)
✅ Offline access: Refresh tokens with user consent
❌ Service accounts: Creates independent server identity (REJECTED)
## Alternative
If service account pattern is truly needed, use BasicAuth mode instead of
OAuth mode. OAuth mode MUST maintain "act on-behalf-of" semantics.
Related: c12df98 (revert of service account test)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
The Keycloak integration enables testing ADR-002 Tier 1 (offline access with refresh tokens):
510
+
The Keycloak integration enables testing ADR-002's primary authentication pattern (offline access with refresh tokens):
511
511
512
512
1.**Refresh token storage**: Tokens stored encrypted in SQLite (`/app/data/tokens.db`)
513
513
2.**Token refresh**: Access tokens refreshed automatically when expired
514
514
3.**Background workers**: Can access APIs using stored refresh tokens
515
515
4.**No admin credentials**: All operations use user's OAuth tokens
516
516
517
+
**Note**: Service account tokens (client_credentials grant) were considered but rejected as they create Nextcloud user accounts and violate OAuth "act on-behalf-of" principles. See ADR-002 "Will Not Implement" section.
518
+
517
519
See `docs/ADR-002-vector-sync-authentication.md` for architectural details.
Accepted - Tier 2 (Token Exchange with Delegation) Implemented
5
+
6
+
**Important**: Service account tokens (old Tier 1) have been rejected as they violate OAuth "act on-behalf-of" principles by creating Nextcloud user accounts for the MCP server.
5
7
6
8
## Context
7
9
@@ -43,26 +45,28 @@ We will implement a **tiered OAuth authentication strategy** for background oper
43
45
44
46
**Note**: This ADR applies only to **OAuth mode**. In BasicAuth mode (single-user deployments), credentials are already available via environment variables, and background operations work without additional configuration.
45
47
46
-
### Tier 1: Service Account Token (client_credentials) ✅ **IMPLEMENTED**
48
+
### OAuth "Act On-Behalf-Of" Principle
47
49
48
-
**Most Compatible Option** - Works with all OIDC providers supporting `client_credentials`
50
+
**Core Requirement**: The MCP server must NEVER create its own user identity in Nextcloud when operating in OAuth mode.
49
51
50
-
- MCP server obtains service account token via `client_credentials` grant
51
-
- Background worker uses service account token directly
Copy file name to clipboardExpand all lines: docs/audience-validation-setup.md
+5-3Lines changed: 5 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -389,9 +389,11 @@ Security: Refresh tokens stored encrypted, rotated on use
389
389
390
390
## Authentication Strategies for Background Jobs
391
391
392
-
### Current Approach: Offline Access with Refresh Tokens (Tier 1)
392
+
> **Note on Service Account Tokens**: Service account tokens (`client_credentials` grant) were evaluated but **rejected** as they create Nextcloud user accounts (e.g., `service-account-{client_id}`) which violates OAuth "act on-behalf-of" principles. See ADR-002 "Will Not Implement" section for details.
393
393
394
-
The MCP server currently uses **offline_access** scope to enable background operations:
394
+
### Current Approach: Offline Access with Refresh Tokens
395
+
396
+
The MCP server uses **offline_access** scope to enable background operations:
395
397
396
398
**How it works:**
397
399
1. User grants `offline_access` scope during OAuth consent
@@ -412,7 +414,7 @@ The MCP server currently uses **offline_access** scope to enable background oper
412
414
- ⚠️ Weak audit trail - API requests appear to come from user directly
413
415
- ⚠️ No visibility that MCP Server is the actual actor
414
416
415
-
### Future Enhancement: Token Exchange with Delegation (Tier 2)
417
+
### Token Exchange with Delegation (ADR-002 Tier 2 - Implemented)
416
418
417
419
**RFC 8693 Delegation** would provide better audit trail and security:
Copy file name to clipboardExpand all lines: docs/oauth-impersonation-findings.md
+17Lines changed: 17 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,23 @@
5
5
**Status**: Implementation Complete - Token Exchange Working
6
6
**Conclusion**: Keycloak Standard Token Exchange (RFC 8693) working for internal-to-internal token exchange. User impersonation requires Legacy V1.
7
7
8
+
---
9
+
10
+
## ⚠️ IMPORTANT UPDATE (2025-11-02)
11
+
12
+
**This document contains outdated information regarding service account tokens.**
13
+
14
+
After implementation and testing, we discovered that service account tokens (`client_credentials` grant) **violate OAuth "act on-behalf-of" principles** by creating Nextcloud user accounts (e.g., `service-account-nextcloud-mcp-server`). This approach has been **REJECTED** and moved to ADR-002's "Will Not Implement" section.
15
+
16
+
**Key Changes:**
17
+
- ❌ **Service account tokens (client_credentials) are INVALID** - Creates user accounts, breaks audit trail
18
+
- ✅ **Token exchange (RFC 8693) is the correct approach** - Implemented and working (ADR-002 Tier 2)
19
+
- ✅ **Offline access with refresh tokens** - Still valid for background operations (ADR-002 primary approach)
20
+
21
+
**For current architecture, see**: `docs/ADR-002-vector-sync-authentication.md`
22
+
23
+
---
24
+
8
25
## Summary
9
26
10
27
We investigated options for implementing user impersonation to enable background operations without requiring admin credentials (ADR-002 Tier 2). Here are the findings:
0 commit comments