Skip to content

feat: wire up credential exchange via RFC 8693 token exchange#7

Merged
tumberger merged 1 commit intomainfrom
04-06-feat_wire_up_credential_exchange_via_rfc_8693_token_exchange
Apr 8, 2026
Merged

feat: wire up credential exchange via RFC 8693 token exchange#7
tumberger merged 1 commit intomainfrom
04-06-feat_wire_up_credential_exchange_via_rfc_8693_token_exchange

Conversation

@tumberger
Copy link
Copy Markdown
Contributor

@tumberger tumberger commented Apr 6, 2026

Summary

  • Export DiscoverEndpoints and OAuthMetadata from the auth package so run.go can call OAuth discovery
  • Replace the exchangeCredential stub with a real implementation that calls POST /oauth2/token using RFC 8693 token exchange
  • The user's access token is the subject_token — no client secret needed (public client)
  • Works for both OAuth tokens and API keys (both returned via access_token field)

Note

Based on feat/governance-telemetry-pipeline — the credential exchange imports backend, sidecar, and proto types introduced there. Should be merged after that branch lands on main.

Test plan

  • kontext start with a .env.kontext containing GITHUB_TOKEN={{kontext:github}} resolves credentials after backend gate is relaxed (kontext-dev/kontext#410)
  • Provider not connected → opens browser to connect flow, retries on Enter
  • Expired/invalid session → triggers re-login before exchange

Depends on

  • kontext-dev/kontext#413 — backend gate relaxation (allows public clients with verified user tokens)

🤖 Generated with Claude Code

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor Author

tumberger commented Apr 6, 2026

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 3 new potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

"client_id": {auth.DefaultClientID},
"subject_token": {session.AccessToken},
"subject_token_type": {"urn:ietf:params:oauth:token-type:access_token"},
"resource": {entry.Provider},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 entry.Resource is parsed from credential template but silently ignored in token exchange

The credential template parser (internal/credential/credential.go:59) supports a provider/resource syntax (e.g., {{kontext:github/readonly}}), populating entry.Resource with the sub-resource specifier. However, exchangeCredential only sends entry.Provider in the resource form field at line 207 and completely ignores entry.Resource. This means if a user specifies {{kontext:github/readonly}}, the readonly scope is silently dropped from the token exchange request, and the returned token may have broader permissions than intended.

Prompt for agents
The credential template parser in internal/credential/credential.go supports provider/resource syntax (e.g., github/readonly), storing the resource part in entry.Resource. But exchangeCredential in internal/run/run.go:207 only uses entry.Provider as the resource form field and completely ignores entry.Resource.

Possible approaches:
1. Include entry.Resource as an additional form parameter (e.g., scope) in the token exchange request.
2. Combine provider and resource into the resource field, e.g., entry.Provider + "/" + entry.Resource when entry.Resource is non-empty.
3. If the server doesn't support resource sub-specifiers yet, add a warning log when entry.Resource is non-empty so users know it's being ignored.

The right approach depends on what the server-side token exchange endpoint supports.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

tumberger commented Apr 8, 2026

Merge activity

  • Apr 8, 10:41 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 8, 10:43 AM UTC: Graphite couldn't merge this PR because it had merge conflicts.

@tumberger tumberger changed the base branch from feat/governance-telemetry-pipeline to graphite-base/7 April 8, 2026 10:42
@tumberger tumberger changed the base branch from graphite-base/7 to main April 8, 2026 10:42
Squashed PR #7 + #13 onto main after resolving squash-merge divergence.

Changes from PR #7 (credential exchange):
- Replace stub exchangeCredential with real RFC 8693 token exchange
- Use session.IssuerURL for endpoint discovery (not hardcoded default)
- Add Bearer auth header to token exchange requests
- Fix filterArgs to handle --flag=value syntax (security: prevents
  --settings=evil.json from bypassing the governance hooks filter)
- Add truncateID helper for safe session ID display

Changes from PR #13 (token refresh):
- Replace static access token with TokenSource function
- Auto-refresh OIDC token during long-running sessions
- Resolve credentials before starting sidecar (data race fix)

Addresses Devin review findings on PR #7.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tumberger tumberger force-pushed the 04-06-feat_wire_up_credential_exchange_via_rfc_8693_token_exchange branch from f4b56ab to 3df8073 Compare April 8, 2026 10:57
@tumberger tumberger merged commit 0eb1840 into main Apr 8, 2026
2 of 3 checks passed
@michiosw michiosw deleted the 04-06-feat_wire_up_credential_exchange_via_rfc_8693_token_exchange branch April 10, 2026 09:05
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.

1 participant