Skip to content

feat(cli): add oauth client-credentials profiles - #1154

Merged
aaltshuler merged 13 commits into
ModernRelay:mainfrom
aaltshuler:codex/workload-client-credentials
Oct 29, 2026
Merged

aaltshuler merged 13 commits into
ModernRelay:mainfrom
aaltshuler:codex/workload-client-credentials

Conversation

@aaltshuler

@aaltshuler aaltshuler commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

RFC 0059 separates credential acquisition from target selection. Unattended clients currently need a pre-issued bearer or an external helper to use OAuth client credentials. This adds one optional oauth_client_credentials profile provider for existing cluster, graph and stdio MCP commands. No commands or organization-administration operations are added.

The provider makes a bounded HTTPS client_secret_post exchange using an explicit endpoint, client ID and environment/file secret reference. It requires a positive finite expires_in, uses system trust and direct networking independently of the managed profile's transport, and keeps credentials in invocation memory. Provider service permissions govern organization operations; applied server policy governs graph and deployment operations.

  • OAuth renewal pins the verified organization, principal, kind, subject, client ID and assurance. Existing token and exec providers retain organization-and-principal continuity, allowing key metadata and service permissions to change without stripping verified metadata.
  • Only expiry before dispatch or a typed pre-issuance expiry refusal permits renewal. Static sources preserve the original refusal. Submitted operations, HTTP authentication refusals and uncertain results are never replayed.
  • Shared custody selection preserves existing providers' persistent explicit cluster token behavior while OAuth remains memory-only. A fresh OAuth --clear reports local_credential_removed: false, does not probe older persistent custody and performs no remote revocation.
  • Provider 429/5xx failures report unavailability; other non-success responses report refusal. The exchange has one total timeout, redirects/retries remain disabled, and availability probes share the existing env/file implementation. The MCP expiry test documents its process-startup headroom rather than implying an authentication margin.

Validation at final integration head 7794f31f (normal merge of main b9035d5a): all 379 CLI unit tests and 61 actual-process scenarios pass with matching CLI/server binaries; nine existing unit and five process nightly cases remain ignored. Four unit and two process regressions first reproduced the review findings and now pass, covering legacy identity rotation, original static-source refusal preservation, truthful clear, and provider error classification. Formatting, AGENTS links, all 422 Markdown checks and release-note preview pass. All required CI checks pass on this exact head (28 distinct passing checks; four conditional jobs skipped). Independent code review found no remaining issue in the working patch; human review threads remain open for re-review.

Tests use local HTTPS identity-provider fixtures. Provider-specific live activation remains separate. The branch incorporates current main, including #1179 and #1124.

@aaltshuler
aaltshuler marked this pull request as ready for review October 28, 2026 18:29

@ragnorc ragnorc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 4cefec2. Two behaviour points to settle before this leaves draft:

  • The renewal identity pin is wider for existing exec and token profiles (managed/auth.rs).
  • With OAuth, cluster token --clear reports a removal it cannot perform (managed/data.rs).

The other inline comments are smaller: interoperability (expires_in, mapping 5xx to "refused", the profile transport), error detail for static profiles, two duplications and a 16 s test sleep.

One interaction I checked: #1185 makes the server answer an unadmitted OIDC subject with 403 not_admitted and no challenge. This PR only reacquires after local expiry or the typed near-expiry issuance refusal, so a 403 cannot start a reacquisition loop.

@aaltshuler
aaltshuler merged commit ea89506 into ModernRelay:main Oct 29, 2026
36 of 38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants