From 5deb3132c3db9680c426b104351f5be72c49c041 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Wed, 5 Nov 2025 19:03:35 +0100 Subject: [PATCH] fix: Correct OAuth token audience validation for multi-audience mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix two issues preventing OAuth tests from passing: 1. Set oidc_client_id and oidc_client_secret on Settings object - These were being read from environment but not propagated to the UnifiedTokenVerifier settings instance 2. Use client_issuer instead of issuer for JWT validation - client_issuer accounts for NEXTCLOUD_PUBLIC_ISSUER_URL override - Fixes "Invalid issuer" errors when public URL differs from internal 3. Accept resource URL with /mcp path in audience validation - During DCR, resource_url is registered as "{mcp_server_url}/mcp" - Tokens correctly include this full path as audience - Verifier now accepts both "http://localhost:8001" and "http://localhost:8001/mcp" as valid MCP audiences These changes restore OAuth functionality while maintaining ADR-005 security requirements for proper audience validation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- nextcloud_mcp_server/app.py | 7 ++++++- nextcloud_mcp_server/auth/unified_verifier.py | 12 +++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/nextcloud_mcp_server/app.py b/nextcloud_mcp_server/app.py index 501e4a0..35a79f2 100644 --- a/nextcloud_mcp_server/app.py +++ b/nextcloud_mcp_server/app.py @@ -573,6 +573,10 @@ async def setup_oauth_config(): settings = get_settings() # Override with discovered values if not set in environment + if not settings.oidc_client_id: + settings.oidc_client_id = client_id + if not settings.oidc_client_secret: + settings.oidc_client_secret = client_secret if not settings.jwks_uri: settings.jwks_uri = jwks_uri if not settings.introspection_uri: @@ -580,7 +584,8 @@ async def setup_oauth_config(): if not settings.userinfo_uri: settings.userinfo_uri = userinfo_uri if not settings.oidc_issuer: - settings.oidc_issuer = issuer + # Use client_issuer which handles public URL override + settings.oidc_issuer = client_issuer if not settings.nextcloud_mcp_server_url: settings.nextcloud_mcp_server_url = mcp_server_url if not settings.nextcloud_resource_uri: diff --git a/nextcloud_mcp_server/auth/unified_verifier.py b/nextcloud_mcp_server/auth/unified_verifier.py index 32d57dd..0cb4b05 100644 --- a/nextcloud_mcp_server/auth/unified_verifier.py +++ b/nextcloud_mcp_server/auth/unified_verifier.py @@ -218,10 +218,13 @@ class UnifiedTokenVerifier(TokenVerifier): audiences_set = set(audiences) - # MCP must have at least one: client_id OR server_url + # MCP must have at least one: client_id OR server_url OR server_url/mcp mcp_valid = self.settings.oidc_client_id in audiences_set or ( self.settings.nextcloud_mcp_server_url - and self.settings.nextcloud_mcp_server_url in audiences_set + and ( + self.settings.nextcloud_mcp_server_url in audiences_set + or f"{self.settings.nextcloud_mcp_server_url}/mcp" in audiences_set + ) ) # Nextcloud must have its resource URI @@ -251,7 +254,10 @@ class UnifiedTokenVerifier(TokenVerifier): self.settings.oidc_client_id in audiences_set or ( self.settings.nextcloud_mcp_server_url - and self.settings.nextcloud_mcp_server_url in audiences_set + and ( + self.settings.nextcloud_mcp_server_url in audiences_set + or f"{self.settings.nextcloud_mcp_server_url}/mcp" in audiences_set + ) ) )