fix: conditionally include offline_access based on IdP discovery
AWS Cognito provides refresh tokens automatically with the authorization code flow but does not list offline_access as a supported scope. Check the IdP's scopes_supported discovery field before including it in requests, and always accept refresh tokens from responses regardless. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
776e2ce693
commit
7730f926cb
@@ -85,10 +85,11 @@ async def oauth_login(request: Request) -> RedirectResponse | JSONResponse:
|
||||
mcp_server_url = oauth_config["mcp_server_url"]
|
||||
callback_uri = f"{mcp_server_url}/oauth/callback"
|
||||
|
||||
# Request only basic OIDC scopes for browser session
|
||||
# Request only basic OIDC scopes for browser session.
|
||||
# offline_access is added conditionally below based on IdP discovery.
|
||||
# Note: Nextcloud app scopes (notes.read, etc.) are for MCP client access tokens,
|
||||
# not for the MCP server's own browser authentication
|
||||
scopes = "openid profile email offline_access"
|
||||
scopes = "openid profile email"
|
||||
|
||||
# Generate PKCE values for ALL modes (both external and integrated IdP require PKCE)
|
||||
code_verifier = secrets.token_urlsafe(32)
|
||||
@@ -113,6 +114,12 @@ async def oauth_login(request: Request) -> RedirectResponse | JSONResponse:
|
||||
if not oauth_client.authorization_endpoint:
|
||||
await oauth_client.discover()
|
||||
|
||||
# Check if IdP supports offline_access via server metadata from discovery
|
||||
idp_metadata = getattr(oauth_client, "server_metadata", None) or {}
|
||||
idp_scopes = idp_metadata.get("scopes_supported")
|
||||
if idp_scopes is None or "offline_access" in idp_scopes:
|
||||
scopes += " offline_access"
|
||||
|
||||
# Get Nextcloud resource URI for audience (background sync needs Nextcloud-scoped tokens)
|
||||
nextcloud_resource_uri = oauth_config.get(
|
||||
"nextcloud_resource_uri", oauth_config.get("nextcloud_host")
|
||||
@@ -151,6 +158,14 @@ async def oauth_login(request: Request) -> RedirectResponse | JSONResponse:
|
||||
discovery = response.json()
|
||||
authorization_endpoint = discovery["authorization_endpoint"]
|
||||
|
||||
# Include offline_access only if the IdP advertises it (or if
|
||||
# scopes_supported is absent from the discovery document).
|
||||
# IdPs like AWS Cognito provide refresh tokens automatically without
|
||||
# supporting the offline_access scope.
|
||||
idp_scopes = discovery.get("scopes_supported")
|
||||
if idp_scopes is None or "offline_access" in idp_scopes:
|
||||
scopes += " offline_access"
|
||||
|
||||
# Replace internal Docker hostname with public URL
|
||||
public_issuer = os.getenv("NEXTCLOUD_PUBLIC_ISSUER_URL")
|
||||
if public_issuer:
|
||||
|
||||
Reference in New Issue
Block a user