Skip to content

fix(auth): support first-party Anthropic OAuth#45

Merged
BunsDev merged 1 commit into
mainfrom
nova/first-party-anthropic-oauth
Jun 6, 2026
Merged

fix(auth): support first-party Anthropic OAuth#45
BunsDev merged 1 commit into
mainfrom
nova/first-party-anthropic-oauth

Conversation

@BunsDev
Copy link
Copy Markdown
Member

@BunsDev BunsDev commented Jun 6, 2026

Summary

Restores Anthropic OAuth/PKCE support without reusing Claude Code OAuth credentials.

  • API keys remain supported.
  • Anthropic OAuth login is available when Coven Code is configured with COVEN_CODE_ANTHROPIC_OAUTH_CLIENT_ID.
  • New OAuth tokens are tagged with the client ID that minted them.
  • Old borrowed Claude.ai bearer tokens remain disabled and no longer count as logged in.
  • Auth/onboarding/docs copy points users to either API keys or a configured first-party OAuth client.

Verification

  • rustfmt --edition 2021 --check crates/cli/src/oauth_flow.rs
  • cargo test -p claurst-core test_oauth_bearer_token_requires_configured_client_id -- --nocapture
  • cargo test -p claurst --no-default-features --bin coven-code oauth_flow -- --nocapture
  • cargo check -p claurst-core
  • cargo check -p claurst-api
  • cargo check -p claurst --no-default-features
  • git diff --check origin/main...HEAD
  • Runtime smoke: old borrowed Claude.ai bearer token reports loggedIn: false, authMethod: none, and disabledTokenSource.
  • Runtime smoke: configured first-party bearer token reports loggedIn: true, authMethod: claude.ai, and tokenSource: claude.ai.

Co-authored-by: Nova nova@openclaw.ai

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>
Copilot AI review requested due to automatic review settings June 6, 2026 00:30
@BunsDev BunsDev merged commit b2ef783 into main Jun 6, 2026
1 check passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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_ID is set, including token exchange and optional API-key creation for Console flow.
  • Tags stored OAuth tokens with oauth_client_id and 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")
};
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