1mod 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#[derive(Clone, Default)]
45pub enum Auth {
46 ApiKey(String),
48 #[default]
50 FromEnv,
51 #[cfg(feature = "cli-integration")]
54 ClaudeCli,
55 OAuth { token: String },
57 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 pub fn resolved(credential: Credential) -> Self {
112 Self::Resolved(credential)
113 }
114
115 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 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}