fix(mcp): request openid scope on interactive OIDC so downstream APIs accept the token - #1091
Conversation
… accept the token Co-Authored-By: AJ Steers <aj@airbyte.io>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksTesting This PyAirbyte VersionYou can test this version of PyAirbyte using the following: # Run PyAirbyte CLI from this branch:
uvx --from 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1784931658-cloud-mcp-oidc-openid-scope' pyairbyte --help
# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1784931658-cloud-mcp-oidc-openid-scope'PR Slash CommandsAirbyte Maintainers can execute the following slash commands on your PR:
📚 Show Repo GuidanceHelpful ResourcesCommunity SupportQuestions? Join the #pyairbyte channel in our Slack workspace. |
There was a problem hiding this comment.
Pull request overview
Updates the interactive OIDC transport-auth configuration for the airbyte-mcp-http server so that it requests and enforces standard OIDC scopes (including openid), ensuring downstream Airbyte Cloud API calls accept the minted token.
Changes:
- Add configurable
required_scopesfor interactive OIDC viaAIRBYTE_MCP_OIDC_SCOPES, defaulting toopenid email profile. - Wire the new scopes into the
OIDCAuthConfigcreated by_create_auth(). - Add unit tests covering the default scopes and the env-var override behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
airbyte/mcp/server.py |
Introduces OIDC_SCOPES_ENV/DEFAULT_OIDC_SCOPES and passes required_scopes into OIDCAuthConfig during auth provider construction. |
tests/unit_tests/test_mcp_auth.py |
Adds assertions that default OIDC scopes include openid, and verifies AIRBYTE_MCP_OIDC_SCOPES overrides are honored. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
📝 WalkthroughWalkthroughThe MCP server adds environment-driven OIDC scopes, defaults to ChangesOIDC scope configuration
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant Environment
participant _resolve_oidc_scopes
participant _create_auth
participant OIDCAuthConfig
Environment->>_resolve_oidc_scopes: provide AIRBYTE_MCP_OIDC_SCOPES
_resolve_oidc_scopes->>_create_auth: return ordered required scopes
_create_auth->>OIDCAuthConfig: set required_scopes
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: AJ Steers <aj@airbyte.io>
Code Coverage OverviewLanguages: Python Python / code-coverage/pytest-fastThe overall coverage in commit 4ca28e5 in the Show a code coverage summary of the most impacted files.
Python / code-coverage/pytest-no-credsThe overall coverage in commit 4ca28e5 in the Show a code coverage summary of the most impacted files.
Python / code-coverage/pytestThe overall coverage in commit 4ca28e5 in the Show a code coverage summary of the most impacted files.
Updated |
…IDC_SCOPES Co-Authored-By: AJ Steers <aj@airbyte.io>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
airbyte/mcp/server.py:205
- This docstring and the default resolution still reference
AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES; if the constant is renamed toDEFAULT_OIDC_SCOPES, update the reference here as well so the docs match the behavior.
configured = _env_or_default(OIDC_SCOPES_ENV, AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES).split()
… email profile Co-Authored-By: AJ Steers <aj@airbyte.io>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
airbyte/mcp/server.py:149
- The PR description says interactive OIDC scopes are configurable via an
AIRBYTE_MCP_OIDC_SCOPESenv var, but the code currently hard-codesAIRBYTE_CLOUD_REQUIRED_OIDC_SCOPESand does not expose an override. Also, the constant name reads Cloud-specific even though this module describes itself as a generic library mapping env vars into auth config.
# Upstream authorize scopes requested for the interactive OIDC flow, also
# advertised to clients via DCR/`.well-known` and enforced on the verified
# upstream token. `openid` is required for OIDC: without it the IdP may issue an
# identity-only token that downstream APIs reject.
AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES: str = "openid email profile"
airbyte/mcp/server.py:287
required_scopesis currently derived from a hard-coded string. If scopes are intended to be configurable (per PR description), read them fromAIRBYTE_MCP_OIDC_SCOPESwith a default, and enforce inclusion ofopenidso a misconfigured override can't silently produce identity-only tokens again.
base_url=base_url,
required_scopes=AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES.split(),
Summary
AJ asked for this fix (the cloud-mcp half; the ops-mcp half is airbytehq/airbyte-ops-mcp#1170). The interactive OIDC MCP server (
airbyte airbyte-mcp-http, deployed as cloud-mcp) authenticated the transport but every downstream Airbyte Cloud API call returned401. Root cause: the upstream token minted for interactive clients carriedscope=email profile— an identity-only token with noopenid— which Airbyte Cloud rejects. The MCP flow droppedopenidbecause_create_auth()leftOIDCAuthConfig.required_scopesunset, soOIDCProxyadvertised no valid scopes and clients could not requestopenid(DCR rejected it). The fix is server-side.OIDC_SCOPES_ENV = "AIRBYTE_MCP_OIDC_SCOPES" # override for non-standard realms DEFAULT_OIDC_SCOPES = "openid email profile" OIDCAuthConfig( ..., + required_scopes=_env_or_default(OIDC_SCOPES_ENV, DEFAULT_OIDC_SCOPES).split(), )The proxy now (1) advertises
openid email profilevia DCR/.well-known, (2) requests them on the upstream/authorize, and (3) enforces them on the verified token. The default is the provider-neutral standard OIDC set (this is the generic library); a deployment can override viaAIRBYTE_MCP_OIDC_SCOPES. Headless bearer/JWT behavior is untouched.Testing
The equivalent change was proven end-to-end locally on the sibling ops-mcp server (same FastMCP
OIDCProxywiring): the full MCP client → proxy → Keycloak → callback → token-swap flow yielded a forwarded token withscope=openid email profileand read-only Cloud tools returning200(was401). Controlled webapp-token comparison isolatedopenidas the single decisive variable (openidpresent →200, absent →401, withaud=accountunchanged in both).Unit tests added in
tests/unit_tests/test_mcp_auth.pyassert the defaultrequired_scopes == ["openid","email","profile"]and the env override.ruff check,ruff format --check,pyrefly check, andpytest tests/unit_tests/test_mcp_auth.py(22 passed) all pass locally.Link to Devin session: https://app.devin.ai/sessions/a5b9501ef92c412aad0408b7c74ef9c8
Requested by: Aaron ("AJ") Steers (@aaronsteers)
Summary by CodeRabbit
AIRBYTE_MCP_OIDC_SCOPESenvironment variable.openid,email, andprofile.openidalways guaranteed (even if omitted in the override).openidis always included.Important
Auto-merge enabled.
This PR is set to merge automatically when all requirements are met.