Skip to content

feat(mcp): confidential OAuth clients via client_secret_env (revives #5060)#6260

Merged
houko merged 3 commits into
mainfrom
feat/mcp-oauth-client-secret-env
Jun 21, 2026
Merged

feat(mcp): confidential OAuth clients via client_secret_env (revives #5060)#6260
houko merged 3 commits into
mainfrom
feat/mcp-oauth-client-secret-env

Conversation

@houko

@houko houko commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Revives the confidential-OAuth-client feature from #5060 (originally by @f-liva), rebased onto current main.
#5060 was closed as stale — explicitly not a rejection ("This is not a rejection of the underlying idea... please rebase onto current main... and open a fresh PR").
This is that fresh PR.

Adds client_secret_env to McpOAuthConfig so MCP servers that require a client_secret in the token-refresh body (e.g. Google Workspace MCP previews: gmailmcp / calendarmcp / drivemcp / chatmcp) work with confidential OAuth clients while still using PKCE.
The secret value never lands in config.toml — only the env-var name is persisted; the value is read from the environment, wrapped in zeroize::Zeroizing, stored in the existing credential vault, and reused on initial exchange and refresh.

Commits

  • feat(mcp-oauth): add client_secret_env for confidential OAuth clients — original feature, authorship preserved (@f-liva).
  • fix(mcp): set client_secret_env in test McpOAuthConfig + refresh secrets baseline — original follow-up.
  • fix(mcp): add client_secret_env to mcp_oauth_integration test McpOAuthConfig — new here.

What changed vs the original #5060

  • Rebased the two original commits onto current main (the original merge-base was ~81 commits back). The feature commit cherry-picked clean; only .secrets.baseline conflicted and was resolved by regenerating it (one new entry: a doc-example string in types.rs, a false positive now baselined).
  • Fixed the recurring E0063: missing field client_secret_env in initializer of McpOAuthConfig that blocked feat(mcp): support confidential OAuth clients via client_secret_env #5060 each time main moved. McpOAuthConfig derives Default but the struct literal in crates/librefang-runtime/tests/mcp_oauth_integration.rs does not use ..Default::default(), so the new field is mandatory there — added client_secret_env: None.
  • Statically verified every McpOAuthConfig { .. } literal in the tree (installer.rs, mcp_oauth.rs, mcp_oauth_integration.rs) now sets the field.

Verification

  • Cherry-picks applied cleanly; baseline regenerated with detect-secrets scan --baseline .secrets.baseline (no unbaselined secrets).
  • Static check of all McpOAuthConfig struct literals (the E0063 class) — done, all set the field.
  • Not locally compiled: this host has no native cargo and the Docker dev image is unavailable right now, so cargo check / cargo test / the schema-golden regen could not be run locally. CI must confirm compile + kernel_config_schema golden + the runtime/api test lanes across platforms. Draft until green.

For reviewers

The original design was already reviewed favourably on #5060 (PKCE preserved, env→vault→zeroize secret handling, fail-fast when DCR is attempted with client_secret_env set).
Please re-check the reconciliation with the OAuth redaction system (redact_token_endpoint_response) that landed on main after the original merge-base — the original branch carried a narrower body-scrub; this rebase keeps main's version.

Refs #5060.

Federico Liva and others added 3 commits June 21, 2026 09:50
Adds `McpOAuthConfig.client_secret_env` field so operators can declare
which environment variable holds the OAuth client secret for confidential
providers (e.g. Google Workspace MCP servers that reject refresh
requests without `client_secret`).

Flow: auth_start resolves env var -> persists to vault -> auth_callback
and try_refresh include client_secret in form params. Pure PKCE clients
(client_secret_env unset) are unaffected.

Addresses all review blockers from PR #5060 v1:
- Ground-up rebase on upstream/main preserves #5609 (RefreshError enum,
  single-flight lock, classify_refresh_failure), #5526 (DCR body
  redaction via redact_token_endpoint_response), and #5069 regression
  test (vault_set_twice_round_trips_via_env_key)
- Bug-D ordering: DCR incompatibility check runs BEFORE vault_set so no
  stale secret is persisted on misconfiguration
- New integration test: client_secret_env_vault_round_trip pins the
  vault storage contract
- Golden fixture regenerated against current main
…ets baseline

The new client_secret_env field made an OAuth test initializer
non-exhaustive after the main merge; set it to None. Refresh
.secrets.baseline for the new client_secret_env doc-example env var name
(false positive, consistent with the existing example entries).
…hConfig

The cherry-picked feature adds client_secret_env: Option<String> to McpOAuthConfig.
The struct-literal in crates/librefang-runtime/tests/mcp_oauth_integration.rs constructs the config without ..Default::default(), so the new field is mandatory there too — otherwise E0063 breaks the runtime test-build lanes (the exact blocker flagged on #5060).
@github-actions github-actions Bot added area/runtime Agent loop, LLM drivers, WASM sandbox area/kernel Core kernel (scheduling, RBAC, workflows) area/security Security systems and auditing size/L 250-999 lines changed labels Jun 21, 2026
@houko
houko marked this pull request as ready for review June 21, 2026 01:11
@houko
houko merged commit ab59e2d into main Jun 21, 2026
37 checks passed
@houko
houko deleted the feat/mcp-oauth-client-secret-env branch June 21, 2026 08:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/kernel Core kernel (scheduling, RBAC, workflows) area/runtime Agent loop, LLM drivers, WASM sandbox area/security Security systems and auditing size/L 250-999 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant