-
Notifications
You must be signed in to change notification settings - Fork 614
[FEATURE][AUTH]: Propagate end user identity and context through the CF workflow #1436
Description
🧭 Epic
Title: Propagate End User Identity and Context Through the Gateway Workflow
Goal: Enable secure, verifiable propagation of end user identity and query context through the MCP Gateway pipeline, from the MCP client through to upstream MCP servers and tool plugins.
Why now:
- Tool plugins (IAM, Cedar, OPA) need end user identity for authorization decisions
- Upstream MCP servers may need user context for personalization or access control
- OAuth2 token exchange requires knowing the end user for on-behalf-of flows
- Audit trails must capture the actual end user, not just the service account
- Compliance requirements mandate user-level attribution for all operations
📖 User Stories
US-1: Plugin Developer - Access User Identity in Hooks
As a: Plugin developer building authorization plugins
I want: Access to the authenticated end user's identity and attributes in plugin hooks
So that: I can make authorization decisions based on who is actually invoking the tool
Acceptance Criteria:
Scenario: User identity available in GlobalContext
Given a user "alice@company.com" authenticates via SSO
When a tool pre-invoke hook is called
Then GlobalContext.user should equal "alice@company.com"
And GlobalContext.metadata should include user attributes
Scenario: User attributes from identity provider
Given user "alice" authenticates via Keycloak
And Keycloak returns groups=["engineering", "developers"]
When the plugin accesses GlobalContext.metadata
Then it should include user_groups=["engineering", "developers"]
And it should include user_email, user_name, user_department
Scenario: Service account vs end user distinction
Given a service account "bot-service" makes requests on behalf of "alice"
When the tool is invoked
Then GlobalContext.user should be "alice" (end user)
And GlobalContext.metadata.service_account should be "bot-service"Technical Requirements:
- Populate
GlobalContext.userfrom authenticated identity - Populate
GlobalContext.metadatawith user attributes - Support identity from JWT, SSO, and API tokens
- Handle delegation (service account on behalf of user)
US-2: Upstream MCP Server - Receive User Context
As an: MCP server developer
I want: To receive the end user's identity when the gateway proxies requests
So that: My MCP server can personalize responses or enforce its own access control
Acceptance Criteria:
Scenario: User context in _meta propagation
Given user "alice" invokes a tool via the gateway
And the gateway is configured to propagate user context
When the request reaches the upstream MCP server
Then the _meta field should include user identity
And the upstream server can access _meta.user
Scenario: User context in HTTP headers
Given user "alice" invokes a tool
And the gateway is configured with identity headers
When the request is proxied to upstream
Then X-User-Id header should contain "alice"
And X-User-Email header should contain "alice@company.com"
Scenario: Sensitive attributes filtered
Given user attributes include internal identifiers
When propagating to external MCP servers
Then sensitive attributes should be filtered
And only configured attributes should be forwardedTechnical Requirements:
- Support user context in
_metafield propagation - Support configurable HTTP header propagation
- Allow attribute filtering per gateway/server
- Sign or encrypt user claims for verification
US-3: OAuth Manager - On-Behalf-Of Token Exchange
As a: Platform operator using OAuth-protected MCP servers
I want: The gateway to perform OAuth2 token exchange on behalf of the end user
So that: Upstream MCP servers receive tokens with the correct user identity
Acceptance Criteria:
Scenario: Token exchange for user identity
Given user "alice" authenticates with access token A
And upstream MCP server requires OAuth with scope "mcp:tools"
When the gateway invokes the upstream server
Then the OAuthManager should exchange token A for token B
And token B should have subject="alice"
And token B should have scope="mcp:tools"
Scenario: Cached token reuse
Given a valid exchanged token exists for (alice, upstream-server)
When alice makes another request to the same server
Then the cached token should be reused
And no new token exchange should occur
Scenario: Token exchange failure handling
Given the token exchange endpoint is unavailable
When the gateway attempts to invoke the upstream server
Then the request should fail with appropriate error
And the failure should be logged with user contextTechnical Requirements:
- Implement RFC 8693 Token Exchange
- Cache exchanged tokens with proper TTL
- Support actor claims for delegation
- Handle token exchange failures gracefully
US-4: Auditor - User Attribution in Audit Trail
As an: Auditor reviewing system activity
I want: All audit trail entries to include the end user identity
So that: I can attribute all actions to specific users for compliance
Acceptance Criteria:
Scenario: Tool invocation audit includes user
Given user "alice" invokes tool "query_database"
When the audit trail entry is created
Then the entry should include user_id="alice"
And the entry should include user_email="alice@company.com"
And the entry should include authentication_method="sso"
Scenario: Audit with delegation chain
Given service "automation-bot" acts on behalf of "alice"
When a tool is invoked
Then the audit entry should include end_user="alice"
And the audit entry should include acting_as="automation-bot"
And the delegation chain should be recorded
Scenario: Anonymous user handling
Given authentication is not required
When an anonymous user invokes a public tool
Then the audit entry should include user_id="anonymous"
And the IP address should be recordedTechnical Requirements:
- Extend audit trail schema with user identity fields
- Support delegation chain recording
- Handle anonymous/unauthenticated users
- Include authentication method in audit
🏗 Architecture
Identity Propagation Flow
sequenceDiagram
participant Client as MCP Client
participant Auth as Auth Middleware
participant Gateway as MCP Gateway
participant Plugin as IAM Plugin
participant OAuth as OAuth Manager
participant Upstream as Upstream MCP Server
Client->>Auth: Request with JWT/Session
Auth->>Auth: Validate & extract identity
Auth->>Gateway: Request + UserContext
Gateway->>Gateway: Populate GlobalContext.user
Gateway->>Gateway: Populate GlobalContext.metadata
Gateway->>Plugin: tool_pre_invoke(context)
Note over Plugin: Has access to user identity
Plugin-->>Gateway: authorized
Gateway->>OAuth: Get token for upstream
OAuth->>OAuth: Token exchange (on-behalf-of)
OAuth-->>Gateway: Access token with user claims
Gateway->>Upstream: Request + _meta.user + Auth header
Upstream-->>Gateway: Response
Gateway->>Gateway: Audit with user attribution
Gateway-->>Client: Response
User Context Data Model
classDiagram
class UserContext {
+user_id: str
+email: str
+name: str
+groups: list[str]
+roles: list[str]
+department: str
+attributes: dict
+authentication_method: str
+authenticated_at: datetime
}
class DelegationContext {
+acting_as: str
+on_behalf_of: str
+delegation_chain: list[str]
+original_token: str
}
class GlobalContext {
+request_id: str
+user: str
+tenant_id: str
+server_id: str
+metadata: dict
+state: dict
}
GlobalContext --> UserContext : metadata contains
GlobalContext --> DelegationContext : metadata contains
Identity Sources
flowchart TD
subgraph "Identity Sources"
A[JWT Token]
B[SSO Session]
C[API Token]
D[Basic Auth]
end
subgraph "Identity Extraction"
E[Auth Middleware]
end
subgraph "Context Population"
F[GlobalContext.user]
G[GlobalContext.metadata]
end
subgraph "Consumers"
H[IAM Plugin]
I[Audit Service]
J[OAuth Manager]
K[Upstream MCP Server]
end
A --> E
B --> E
C --> E
D --> E
E --> F
E --> G
F --> H
F --> I
G --> H
G --> J
G --> K
📋 Implementation Tasks
Phase 1: Identity Extraction
- Extract user identity from JWT claims in auth middleware
- Extract user attributes from SSO provider responses
- Extract user info from API token metadata
- Create unified
UserContextmodel
Phase 2: GlobalContext Population
- Populate
GlobalContext.userfrom authenticated identity - Populate
GlobalContext.metadatawith user attributes - Add
UserContextto metadata with full attributes - Handle delegation/impersonation context
Phase 3: Plugin Framework Updates
- Ensure plugins receive populated GlobalContext
- Document user context access patterns for plugin developers
- Add helper methods for common user attribute access
- Update existing plugins to use user context
Phase 4: Upstream Propagation
- Propagate user context in
_metafield - Support configurable HTTP header propagation
- Implement attribute filtering per gateway
- Add signed claims option for verification
Phase 5: OAuth Token Exchange
- Implement RFC 8693 Token Exchange in OAuthManager
- Add on-behalf-of flow support
- Cache exchanged tokens with proper invalidation
- Handle token exchange failures
Phase 6: Audit Trail Enhancement
- Add user identity fields to audit trail schema
- Create Alembic migration for new fields
- Update audit service to capture user context
- Add delegation chain to audit entries
Phase 7: Testing
- Unit tests for identity extraction
- Unit tests for context propagation
- Integration tests for OAuth token exchange
- Integration tests for end-to-end propagation
⚙️ Configuration Examples
Identity Propagation Configuration
# .env or config
IDENTITY_PROPAGATION_ENABLED=true
IDENTITY_PROPAGATION_HEADERS=X-User-Id,X-User-Email,X-User-Groups
IDENTITY_PROPAGATION_META=true
IDENTITY_SENSITIVE_ATTRIBUTES=internal_id,password_hashGateway Configuration for Upstream
{
"name": "Upstream MCP Server",
"url": "https://upstream.example.com/mcp",
"identity_propagation": {
"enabled": true,
"mode": "headers",
"headers": {
"X-User-Id": "user_id",
"X-User-Email": "email"
},
"meta": true,
"sign_claims": true
}
}OAuth Token Exchange Configuration
oauth:
token_exchange:
enabled: true
grant_type: "urn:ietf:params:oauth:grant-type:token-exchange"
subject_token_type: "urn:ietf:params:oauth:token-type:access_token"
requested_token_type: "urn:ietf:params:oauth:token-type:access_token"
cache_ttl_seconds: 300✅ Success Criteria
-
GlobalContext.userpopulated from all auth methods (JWT, SSO, API token) -
GlobalContext.metadataincludes user attributes (email, groups, roles) - Plugins can access user identity in pre/post invoke hooks
- User context propagated to upstream via
_metafield - User context propagated via configurable HTTP headers
- OAuth token exchange works with user identity
- Audit trail includes user attribution for all entries
- Delegation chains properly recorded
- Sensitive attributes filtered from propagation
🏁 Definition of Done
- Identity extraction from all auth methods implemented
- GlobalContext populated with user identity and attributes
- Plugin framework provides user context to hooks
- Upstream propagation via _meta and headers implemented
- OAuth token exchange with on-behalf-of implemented
- Audit trail schema updated with user fields
- Alembic migration created and tested
- Unit tests for all components pass
- Integration tests for end-to-end flow pass
- Documentation for plugin developers updated
- Code passes
make verify - PR reviewed and approved
🔗 Related Issues
- [FEATURE][PLUGIN]: Enhance the IAM pre-tool plugin #1438 - Enhance IAM pre-tool plugin (depends on this)
- [FEATURE]: Dynamic tools/resources based on user context and server-side signals #2171 - Dynamic tools based on user context
- OAuth Manager enhancements
- Audit Trail service
📓 Additional Context
Security Considerations
- User claims should be signed when propagated externally
- Sensitive attributes must be filtered
- Token exchange should use short-lived tokens
- Delegation chains must be verifiable
Standards Compliance
- RFC 8693: OAuth 2.0 Token Exchange
- OpenID Connect for user attributes
- SCIM for user attribute schema