feat: enable authorization services for token exchange in Keycloak
Configure Keycloak authorization policies to allow nextcloud-mcp-server to exchange tokens for nextcloud audience. This enables RFC 8693 token exchange flow between the MCP client and Nextcloud. Changes: - Enable service accounts and authorization services for nextcloud client - Add token-exchange resource with scope-based permissions - Create client policy allowing nextcloud-mcp-server and nextcloud - Add token-exchange-permission with affirmative decision strategy - Add mcp-server-audience mapper to nextcloud-mcp-server client - Simplify audience validation to accept tokens with MCP client ID The authorization policy enables tokens issued to nextcloud-mcp-server to be exchanged for tokens with nextcloud audience, validated via both clients being included in the allow-nextcloud-mcp-server-to-exchange policy. All 7 token exchange integration tests pass, confirming: - Basic token exchange with correct audience claims - Nextcloud API access with exchanged tokens - Stateless multiple exchange operations - Full CRUD operations on Notes API - Proper claim preservation (sub, azp, aud) - Default scope configuration - TokenExchangeService implementation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -140,27 +140,23 @@ class ProgressiveConsentTokenVerifier:
|
||||
|
||||
# Audience validation:
|
||||
# - Accept tokens with no audience (will validate via introspection if needed)
|
||||
# - Accept tokens with MCP client ID in audience
|
||||
# - Reject tokens with "nextcloud" audience (wrong flow)
|
||||
# - Accept tokens with MCP client ID in audience (regardless of other audiences)
|
||||
# - Reject tokens without MCP client ID (if audience is present)
|
||||
if audiences:
|
||||
# Check if this is a Nextcloud token (wrong flow)
|
||||
if "nextcloud" in audiences:
|
||||
# Check if MCP client ID is in the audience
|
||||
if self.mcp_client_id in audiences:
|
||||
logger.debug(
|
||||
f"Token has audience {audiences} - MCP client ID present"
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
f"Token rejected: wrong audience {audiences}, expected {self.mcp_client_id} or no audience"
|
||||
)
|
||||
logger.error(
|
||||
"Received Nextcloud token in MCP context - "
|
||||
"Token does not include MCP client ID in audience - "
|
||||
"client may be using wrong token"
|
||||
)
|
||||
return None
|
||||
|
||||
# If audience is present but doesn't match, log warning but continue
|
||||
# (token might use resource URL instead of client ID)
|
||||
if self.mcp_client_id not in audiences:
|
||||
logger.info(
|
||||
f"Token has audience {audiences}, expected {self.mcp_client_id}. "
|
||||
"Accepting token with non-standard audience (may use resource URL)."
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"Token has no audience claim - accepting for MCP server validation"
|
||||
|
||||
Reference in New Issue
Block a user