fix(auth): support first-party Anthropic OAuth#45
Merged
Conversation
Restore Anthropic PKCE login behind COVEN_CODE_ANTHROPIC_OAUTH_CLIENT_ID so Coven Code does not become API-key-only while still blocking borrowed Claude Code OAuth tokens. Co-authored-by: Nova <nova@openclaw.ai>
There was a problem hiding this comment.
Pull request overview
This PR restores Anthropic OAuth/PKCE login support in Coven Code only when a first-party OAuth client ID is configured, and ensures stored OAuth tokens are attributed to (and validated against) the configured client ID so borrowed/unsupported bearer tokens remain disabled.
Changes:
- Re-enables the CLI OAuth login flow when
COVEN_CODE_ANTHROPIC_OAUTH_CLIENT_IDis set, including token exchange and optional API-key creation for Console flow. - Tags stored OAuth tokens with
oauth_client_idand gates Bearer token usage on matching the configured client ID. - Updates user-facing help text/docs/onboarding copy to reflect the new “configured first-party OAuth client” requirement.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src-rust/crates/tui/src/onboarding_dialog.rs | Updates onboarding provider setup copy to mention OAuth as an alternative to API keys. |
| src-rust/crates/core/src/oauth_config.rs | Adjusts production OAuth commentary to reflect first-party client-ID requirement. |
| src-rust/crates/core/src/lib.rs | Adds COVEN_CODE_ANTHROPIC_OAUTH_CLIENT_ID constant, stores oauth_client_id, and gates Bearer-token auth on configured client match. |
| src-rust/crates/commands/src/lib.rs | Updates /login help text to describe the configured client-ID requirement. |
| src-rust/crates/cli/src/oauth_flow.rs | Implements the Anthropic OAuth PKCE flow (callback server, token exchange, API key creation) and persists tokens with minting client ID. |
| src-rust/crates/cli/src/main.rs | Updates auth-related CLI messaging/status handling around configured-client Bearer tokens. |
| src-rust/crates/api/src/lib.rs | Updates auth error hints to mention configured OAuth client ID + auth login. |
| README.md | Documents configuring COVEN_CODE_ANTHROPIC_OAUTH_CLIENT_ID before using OAuth login. |
| docs/auth.md | Updates OAuth documentation to require first-party client ID and shows the new env var in examples. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+97
to
+105
| let auth_code = wait_for_auth_code_impl(listener, &state) | ||
| .await | ||
| .context("OAuth callback failed")?; | ||
| debug!("OAuth auth code received"); | ||
|
|
||
| let token_resp = | ||
| exchange_code_for_tokens(&client_id, &auth_code, &state, &code_verifier, port, false) | ||
| .await | ||
| .context("Token exchange failed")?; |
Comment on lines
458
to
469
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[tokio::test] | ||
| async fn anthropic_oauth_login_is_disabled() { | ||
| async fn anthropic_oauth_login_requires_first_party_client_id() { | ||
| std::env::remove_var(oauth::CLIENT_ID_ENV); | ||
| let err = run_oauth_login_flow(true) | ||
| .await | ||
| .expect_err("Anthropic OAuth login should be disabled"); | ||
| assert!(err.to_string().contains("application-specific OAuth client")); | ||
| .expect_err("Anthropic OAuth login should require a first-party client ID"); | ||
| assert!(err.to_string().contains(oauth::CLIENT_ID_ENV)); | ||
| } |
Comment on lines
147
to
151
| Line::from(vec![ | ||
| Span::styled(" › ", Style::default().fg(pink)), | ||
| Span::styled("set ANTHROPIC_API_KEY=<key>", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), | ||
| Span::styled(" then restart", Style::default().fg(dim)), | ||
| Span::styled("ANTHROPIC_API_KEY", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)), | ||
| Span::styled(" or configured OAuth", Style::default().fg(dim)), | ||
| ]), |
Comment on lines
+149
to
+172
| let tokens = OAuthTokens { | ||
| access_token: token_resp.access_token.clone(), | ||
| refresh_token: token_resp.refresh_token.clone(), | ||
| expires_at_ms: Some(expires_at_ms), | ||
| scopes: scopes.clone(), | ||
| account_uuid, | ||
| email, | ||
| organization_uuid, | ||
| subscription_type: None, | ||
| oauth_client_id: Some(client_id.clone()), | ||
| api_key: api_key.clone(), | ||
| }; | ||
| tokens | ||
| .save_and_register(label) | ||
| .await | ||
| .context("Failed to save OAuth tokens")?; | ||
|
|
||
| let (credential, use_bearer_auth) = if uses_bearer { | ||
| (token_resp.access_token.clone(), true) | ||
| } else if let Some(key) = api_key { | ||
| (key, false) | ||
| } else { | ||
| bail!("Login succeeded but could not obtain a usable credential") | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Restores Anthropic OAuth/PKCE support without reusing Claude Code OAuth credentials.
COVEN_CODE_ANTHROPIC_OAUTH_CLIENT_ID.Verification
rustfmt --edition 2021 --check crates/cli/src/oauth_flow.rscargo test -p claurst-core test_oauth_bearer_token_requires_configured_client_id -- --nocapturecargo test -p claurst --no-default-features --bin coven-code oauth_flow -- --nocapturecargo check -p claurst-corecargo check -p claurst-apicargo check -p claurst --no-default-featuresgit diff --check origin/main...HEADloggedIn: false,authMethod: none, anddisabledTokenSource.loggedIn: true,authMethod: claude.ai, andtokenSource: claude.ai.Co-authored-by: Nova nova@openclaw.ai