claude_agent/auth/
mod.rs

1//! Authentication module for Claude API.
2//!
3//! The `Auth` enum is the primary entry point for all authentication methods.
4//! SDK users should use `Auth` to configure authentication, which internally
5//! resolves to `Credential` for API requests.
6
7mod cache;
8mod config;
9mod credential;
10mod helper;
11mod provider;
12mod providers;
13#[cfg(feature = "cli-integration")]
14mod storage;
15
16pub use cache::CachedProvider;
17pub use config::{CLAUDE_CODE_BETA, OAuthConfig, OAuthConfigBuilder};
18pub use credential::{Credential, OAuthCredential};
19pub use helper::{ApiKeyHelper, AwsCredentialRefresh, AwsCredentials, CredentialManager};
20pub use provider::CredentialProvider;
21#[cfg(feature = "cli-integration")]
22pub use providers::ClaudeCliProvider;
23pub use providers::{ChainProvider, EnvironmentProvider, ExplicitProvider};
24#[cfg(feature = "cli-integration")]
25pub use storage::CliCredentials;
26
27use crate::Result;
28
29/// Primary authentication configuration for SDK usage.
30///
31/// `Auth` provides a unified interface for all authentication methods.
32/// Use this enum to configure how the SDK authenticates with Claude API.
33///
34/// # Variants
35///
36/// - `ApiKey`: Direct API key authentication
37/// - `FromEnv`: Load API key from ANTHROPIC_API_KEY environment variable
38/// - `ClaudeCli`: Use credentials from Claude Code CLI (requires `cli-integration` feature)
39/// - `OAuth`: OAuth token authentication
40/// - `Resolved`: Pre-resolved credential (for testing or credential reuse)
41/// - `Bedrock`: AWS Bedrock (requires `aws` feature)
42/// - `Vertex`: GCP Vertex AI (requires `gcp` feature)
43/// - `Foundry`: Azure Foundry (requires `azure` feature)
44#[derive(Clone, Default)]
45pub enum Auth {
46    /// Direct API key authentication.
47    ApiKey(String),
48    /// Load API key from ANTHROPIC_API_KEY environment variable.
49    #[default]
50    FromEnv,
51    /// Use credentials from Claude Code CLI (~/.claude/credentials.json).
52    /// Requires `cli-integration` feature.
53    #[cfg(feature = "cli-integration")]
54    ClaudeCli,
55    /// OAuth token authentication.
56    OAuth { token: String },
57    /// Use a pre-resolved credential directly.
58    /// Useful for testing, credential reuse, or custom credential sources.
59    Resolved(Credential),
60    #[cfg(feature = "aws")]
61    Bedrock { region: String },
62    #[cfg(feature = "gcp")]
63    Vertex { project: String, region: String },
64    #[cfg(feature = "azure")]
65    Foundry { resource: String },
66}
67
68impl Auth {
69    pub fn api_key(key: impl Into<String>) -> Self {
70        Self::ApiKey(key.into())
71    }
72
73    pub fn from_env() -> Self {
74        Self::FromEnv
75    }
76
77    #[cfg(feature = "cli-integration")]
78    pub fn claude_cli() -> Self {
79        Self::ClaudeCli
80    }
81
82    pub fn oauth(token: impl Into<String>) -> Self {
83        Self::OAuth {
84            token: token.into(),
85        }
86    }
87
88    #[cfg(feature = "aws")]
89    pub fn bedrock(region: impl Into<String>) -> Self {
90        Self::Bedrock {
91            region: region.into(),
92        }
93    }
94
95    #[cfg(feature = "gcp")]
96    pub fn vertex(project: impl Into<String>, region: impl Into<String>) -> Self {
97        Self::Vertex {
98            project: project.into(),
99            region: region.into(),
100        }
101    }
102
103    #[cfg(feature = "azure")]
104    pub fn foundry(resource: impl Into<String>) -> Self {
105        Self::Foundry {
106            resource: resource.into(),
107        }
108    }
109
110    /// Use a pre-resolved credential directly.
111    pub fn resolved(credential: Credential) -> Self {
112        Self::Resolved(credential)
113    }
114
115    /// Resolve authentication to internal credential format.
116    pub async fn resolve(&self) -> Result<Credential> {
117        match self {
118            Self::ApiKey(key) => Ok(Credential::api_key(key)),
119            Self::FromEnv => EnvironmentProvider::new().resolve().await,
120            #[cfg(feature = "cli-integration")]
121            Self::ClaudeCli => ClaudeCliProvider::new().resolve().await,
122            Self::OAuth { token } => Ok(Credential::oauth(token)),
123            Self::Resolved(credential) => Ok(credential.clone()),
124            #[cfg(feature = "aws")]
125            Self::Bedrock { .. } => Ok(Credential::default()),
126            #[cfg(feature = "gcp")]
127            Self::Vertex { .. } => Ok(Credential::default()),
128            #[cfg(feature = "azure")]
129            Self::Foundry { .. } => Ok(Credential::default()),
130        }
131    }
132
133    pub fn is_cloud_provider(&self) -> bool {
134        #[allow(unreachable_patterns)]
135        match self {
136            #[cfg(feature = "aws")]
137            Self::Bedrock { .. } => true,
138            #[cfg(feature = "gcp")]
139            Self::Vertex { .. } => true,
140            #[cfg(feature = "azure")]
141            Self::Foundry { .. } => true,
142            _ => false,
143        }
144    }
145
146    pub fn is_oauth(&self) -> bool {
147        match self {
148            Self::OAuth { .. } => true,
149            #[cfg(feature = "cli-integration")]
150            Self::ClaudeCli => true,
151            Self::Resolved(cred) => cred.is_oauth(),
152            _ => false,
153        }
154    }
155
156    /// Check if Anthropic's server-side tools (WebSearch, WebFetch) are available.
157    ///
158    /// Server-side tools are available with Anthropic direct API (API Key or OAuth)
159    /// but NOT with cloud providers (Bedrock, Vertex, Foundry).
160    pub fn supports_server_tools(&self) -> bool {
161        !self.is_cloud_provider()
162    }
163}
164
165impl From<&str> for Auth {
166    fn from(key: &str) -> Self {
167        Self::ApiKey(key.to_string())
168    }
169}
170
171impl From<String> for Auth {
172    fn from(key: String) -> Self {
173        Self::ApiKey(key)
174    }
175}
176
177impl From<Credential> for Auth {
178    fn from(credential: Credential) -> Self {
179        Self::Resolved(credential)
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186
187    #[test]
188    fn test_auth_from_str() {
189        let auth: Auth = "sk-test-key".into();
190        assert!(matches!(auth, Auth::ApiKey(_)));
191    }
192
193    #[test]
194    fn test_auth_from_string() {
195        let auth: Auth = "sk-test-key".to_string().into();
196        assert!(matches!(auth, Auth::ApiKey(_)));
197    }
198
199    #[test]
200    fn test_auth_default() {
201        let auth = Auth::default();
202        assert!(matches!(auth, Auth::FromEnv));
203    }
204
205    #[test]
206    fn test_auth_constructors() {
207        assert!(matches!(Auth::api_key("key"), Auth::ApiKey(_)));
208        assert!(matches!(Auth::from_env(), Auth::FromEnv));
209        #[cfg(feature = "cli-integration")]
210        assert!(matches!(Auth::claude_cli(), Auth::ClaudeCli));
211        assert!(matches!(Auth::oauth("token"), Auth::OAuth { .. }));
212        assert!(matches!(
213            Auth::resolved(Credential::api_key("key")),
214            Auth::Resolved(_)
215        ));
216    }
217
218    #[test]
219    fn test_auth_from_credential() {
220        let cred = Credential::api_key("test-key");
221        let auth: Auth = cred.into();
222        assert!(matches!(auth, Auth::Resolved(_)));
223    }
224
225    #[tokio::test]
226    async fn test_auth_resolved_resolve() {
227        let cred = Credential::api_key("test-key");
228        let auth = Auth::resolved(cred);
229        let resolved = auth.resolve().await.unwrap();
230        assert!(!resolved.is_default());
231    }
232}