fix: resolve OAuth compatibility issues for login-flow deployment#664
Conversation
- Drop OIDC fork: comment out third_party/oidc mount, use upstream v1.16.3 from app store (fixes consent redirect race, PR #631) - Support client_secret_basic auth: add _extract_basic_auth() helper so TS MCP SDK can authenticate at token endpoint (RFC 6749 §2.3.1) - Multi-issuer JWT validation: accept tokens with internal Docker issuer (http://app:80) or public URL (NEXTCLOUD_PUBLIC_ISSUER_URL) since AS proxy obtains tokens server-to-server - Introspection fallback: try token introspection when JWT verification fails, supporting both JWT and opaque token types - Register all tool scopes in DCR: add semantic:read, collectives:read, collectives:write to OIDC client allowed_scopes so tokens include them and semantic search tools are visible to authenticated clients - Auto-create Astrolabe OAuth client: new app-hook creates OIDC client and stores credentials in config.php so the "Authorize via OAuth" button works without manual setup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR Review: fix OAuth compatibility issues for login-flow deploymentThis PR addresses three real issues that were blocking Claude Code from authenticating to the login-flow MCP server. The fixes are targeted and the root causes are well-explained in the description. A few items worth discussing before merging: Security
if not client_id:
client_id, _ = _extract_basic_auth(request) # client_secret is thrown awayFor public clients (like Claude Code) that use PKCE, this is fine — they have no secret. But for confidential clients ( Introspection fallback on JWT validation failure ( When JWT verification returns except jwt.InvalidSignatureError:
logger.warning("JWT signature invalid, skipping introspection fallback")
return None
except jwt.InvalidIssuerError as e:
logger.debug(f"JWT issuer mismatch: {e}, trying introspection")
# fall through to introspectionCorrectness
if hasattr(settings, "nextcloud_host") and settings.nextcloud_host:
host = settings.nextcloud_host.rstrip("/")
if host not in self.valid_issuers:
self.valid_issuers.append(host)
Code QualityCommented-out code in CI workflow ( Dead code in CI is noise. If the OIDC fork is definitively dropped, remove the commented block rather than preserving it. The git history captures the deletion. Hardcoded CLIENT_ID="astrolabeMcpClientOAuth00000000000"A fixed client ID is intentional for idempotency (the
This is the right design, but the comment says Minor
SummaryThe core fixes (Basic Auth support, multi-issuer JWT validation, scope registration) are correct and well-motivated. The main items I'd address before merging are: (1) the unanswered question of whether confidential client secrets from Basic Auth should be validated, and (2) replacing the |
…lient creation Move 26-configure-astrolabe-oauth.sh from post-installation (runs once on first boot) to before-starting (runs on every start). This ensures the Astrolabe OIDC client is created as soon as MCP_SERVER_URL is available, even if it wasn't set during initial installation. Also copy 25-configure-mcp-server-url.sh to before-starting so the mcp_server_url config stays current across container recreations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Relax redirect_uri validation to accept HTTPS for remote hosts (e.g., cloud-hosted MCP clients like Claude AI) while keeping HTTP allowed for localhost per RFC 8252 loopback exception. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR Review: fix: resolve OAuth compatibility issues for login-flow deploymentGood set of fixes that address real authentication failures. The overall approach is sound. A few issues worth addressing before merge: Bugs / Security Issues1. Client secret from Basic Auth is not validated (
if not client_id:
client_id, _ = _extract_basic_auth(request)For confidential clients authenticating via 2. Silent issuer bypass when if not skip_issuer_check and self.valid_issuers:
token_issuer = payload.get("iss")
if token_issuer not in self.valid_issuers:
raise jwt.InvalidIssuerError(...)If 3. Hardcoded OAuth client ID in CLIENT_ID="astrolabeMcpClientOAuth00000000000"A predictable, fixed client ID across all deployments makes enumeration trivial. Consider generating a random one (e.g., Minor Issues4. IPv6 loopback not handled in redirect URI validation ( RFC 8252 §8.3 permits 5. Commented-out code in # - name: Build OIDC app
# run: |
# cd third_party/oidc
# ...Git history preserves this; the comment block just adds noise. Either delete it or replace with a single-line comment explaining the change. 6. if hasattr(settings, "oidc_issuer") and settings.oidc_issuer:
...
if hasattr(settings, "nextcloud_host") and settings.nextcloud_host:
...
Positive Notes
Overall: the correctness issues in #1 and #2 should be addressed before merging given their security implications. The rest are polish. |
Summary
third_party/oidcfork (upstream PR fix: Preserve OIDC params across SAML session regeneration H2CK/oidc#631 merged the same consent redirect fix plus SAML session regeneration fixes)client_secret_basicauth: Claude Code's TS MCP SDK sendsclient_idvia HTTP Basic Auth header, not form body — added_extract_basic_auth()helper to token endpointhttp://app:80) but verifier expected public URL (http://localhost:8080) — now accepts bothsemantic:read,collectives:read/writeto OIDC clientallowed_scopesso semantic search tools appear for authenticated clients26-configure-astrolabe-oauth.sh) creates OIDC client and stores credentials inconfig.phpso the "Authorize via OAuth" button works without manual setupContext
Claude Code couldn't authenticate to the login-flow MCP server due to three cascading issues:
client_secret_basic(400: "client_id is required")semantic:readscope wasn't registered in OIDC clientAdditionally, the Astrolabe "Authorize via OAuth" button in Nextcloud settings redirected to
/appbecause no OAuth client was configured for Astrolabe.Test plan
uv run pytest -m login_flow -v --browser firefox— 12 passed, 1 skipped, 1 xfailedhttp://localhost:8004/mcpnc_semantic_search,nc_semantic_search_answer,nc_get_vector_sync_statustools visibleThis PR was generated with the help of AI, and reviewed by a Human