auth_patterns/
auth_patterns.rs1#![allow(clippy::uninlined_format_args)]
2use openai_ergonomic::{Client, Config, Result};
16use std::env;
17
18#[tokio::main]
19async fn main() -> Result<()> {
20 println!("=== Authentication Patterns ===\n");
21
22 println!("1. Environment Variable Authentication:");
24 env_var_auth().await?;
25
26 println!("\n2. Direct API Key:");
28 direct_api_key().await?;
29
30 println!("\n3. Organization Configuration:");
32 organization_config()?;
33
34 println!("\n4. Project Configuration:");
36 project_config()?;
37
38 println!("\n5. Custom Headers:");
40 custom_headers()?;
41
42 println!("\n6. Proxy Configuration:");
44 proxy_config()?;
45
46 println!("\n7. Multiple Client Configurations:");
48 multiple_clients()?;
49
50 println!("\n8. Configuration Validation:");
52 config_validation()?;
53
54 println!("\n9. Secure Key Management:");
56 secure_key_management();
57
58 Ok(())
59}
60
61async fn env_var_auth() -> Result<()> {
62 if env::var("OPENAI_API_KEY").is_err() {
70 println!("Warning: OPENAI_API_KEY not set");
71 println!("Set it with: export OPENAI_API_KEY=your-key-here");
72 return Ok(());
73 }
74
75 let client = Client::from_env()?.build();
77 println!("Client created from environment variables");
78
79 match client.send_chat(client.chat_simple("Hello")).await {
81 Ok(response) => {
82 if let Some(content) = response.content() {
83 println!("Response: {}", content);
84 } else {
85 println!("Response: (no content)");
86 }
87 }
88 Err(e) => println!("Error: {}", e),
89 }
90
91 Ok(())
92}
93
94async fn direct_api_key() -> Result<()> {
95 let api_key = "sk-your-api-key-here"; let config = Config::builder().api_key(api_key).build();
98 let client = Client::builder(config)?.build();
99
100 println!("Client created with direct API key");
101
102 match client.send_chat(client.chat_simple("Hello")).await {
104 Ok(response) => {
105 if let Some(content) = response.content() {
106 println!("Response: {}", content);
107 } else {
108 println!("Response: (no content)");
109 }
110 }
111 Err(e) => println!("Expected error with demo key: {}", e),
112 }
113
114 Ok(())
115}
116
117fn organization_config() -> Result<()> {
118 let config = Config::builder()
120 .api_key("your-api-key")
121 .organization("org-123456789")
122 .build();
123
124 let _client = Client::builder(config)?.build();
125 println!("Client configured with organization ID");
126
127 Ok(())
134}
135
136fn project_config() -> Result<()> {
137 let config = Config::builder()
139 .api_key("your-api-key")
140 .project("proj-abc123")
141 .build();
142
143 let _client = Client::builder(config)?.build();
144 println!("Client configured with project ID");
145
146 Ok(())
152}
153
154fn custom_headers() -> Result<()> {
155 let config = Config::builder().api_key("your-api-key").build();
162
163 let _client = Client::builder(config)?.build();
164 println!("Client configured (custom headers not yet supported)");
165
166 println!("Custom headers feature planned for future implementation");
168
169 Ok(())
170}
171
172fn proxy_config() -> Result<()> {
173 let config = Config::builder().api_key("your-api-key").build();
180
181 let _client = Client::builder(config)?.build();
182 println!("Client configured (proxy support not yet available)");
183
184 println!("Proxy configuration feature planned for future implementation");
186
187 Ok(())
188}
189
190fn multiple_clients() -> Result<()> {
191 use reqwest_middleware::ClientBuilder;
192 use std::time::Duration;
193
194 let prod_http_client = ClientBuilder::new(
198 reqwest::Client::builder()
199 .timeout(Duration::from_secs(60))
200 .build()
201 .expect("Failed to build reqwest client"),
202 )
203 .build();
204
205 let prod_config = Config::builder()
206 .api_key("prod-api-key")
207 .organization("org-prod")
208 .http_client(prod_http_client)
209 .max_retries(5)
210 .build();
211 let prod_client = Client::builder(prod_config)?.build();
212
213 let dev_http_client = ClientBuilder::new(
215 reqwest::Client::builder()
216 .timeout(Duration::from_secs(10))
217 .build()
218 .expect("Failed to build reqwest client"),
219 )
220 .build();
221
222 let dev_config = Config::builder()
223 .api_key("dev-api-key")
224 .organization("org-dev")
225 .api_base("https://api.openai-dev.com") .http_client(dev_http_client)
227 .build();
228 let dev_client = Client::builder(dev_config)?.build();
229
230 let test_config = Config::builder()
232 .api_key("test-api-key")
233 .api_base("http://localhost:8080") .build();
235 let _test_client = Client::builder(test_config)?.build();
236
237 println!("Created multiple clients:");
238 println!("- Production client with retries");
239 println!("- Development client with custom endpoint");
240 println!("- Test client with mock server");
241
242 let _client = if cfg!(debug_assertions) {
244 &dev_client
245 } else {
246 &prod_client
247 };
248
249 println!(
250 "Using {} client",
251 if cfg!(debug_assertions) {
252 "dev"
253 } else {
254 "prod"
255 }
256 );
257
258 Ok(())
259}
260
261fn config_validation() -> Result<()> {
262 fn validate_api_key(key: &str) -> bool {
265 key.starts_with("sk-") && key.len() > 20
267 }
268
269 fn validate_org_id(org: &str) -> bool {
270 org.starts_with("org-") && org.len() > 4
272 }
273
274 let api_key = "sk-test-key-123456789";
275 let org_id = "org-12345";
276
277 if !validate_api_key(api_key) {
278 println!("Warning: API key format appears invalid");
279 }
280
281 if !validate_org_id(org_id) {
282 println!("Warning: Organization ID format appears invalid");
283 }
284
285 if validate_api_key(api_key) {
287 let config = Config::builder()
288 .api_key(api_key)
289 .organization(org_id)
290 .build();
291
292 let _client = Client::builder(config)?.build();
293 println!("Configuration validated and client created");
294 }
295
296 Ok(())
297}
298
299fn secure_key_management() {
300 println!("Secure Key Management Best Practices:");
301 println!();
302
303 println!("1. Never hardcode API keys in source code");
305 println!("2. Use environment variables for local development");
310 if let Ok(key) = env::var("OPENAI_API_KEY") {
311 println!(" API key loaded from environment (length: {})", key.len());
312 }
313
314 println!("3. Use proper secrets management in production:");
316 println!(" - AWS Secrets Manager");
317 println!(" - Azure Key Vault");
318 println!(" - HashiCorp Vault");
319 println!(" - Kubernetes Secrets");
320
321 println!("4. Rotate API keys regularly");
323
324 println!("5. Use different API keys for each environment:");
326 let keys_by_env = vec![
327 ("development", "OPENAI_API_KEY_DEV"),
328 ("staging", "OPENAI_API_KEY_STAGING"),
329 ("production", "OPENAI_API_KEY_PROD"),
330 ];
331
332 for (env_name, env_var) in keys_by_env {
333 if env::var(env_var).is_ok() {
334 println!(" {} key configured", env_name);
335 } else {
336 println!(" {} key not found", env_name);
337 }
338 }
339
340 println!("6. Monitor API key usage:");
342 println!(" - Set up usage alerts");
343 println!(" - Track per-project costs");
344 println!(" - Audit access logs");
345
346 #[cfg(unix)]
348 {
349 use std::fs;
350 use std::os::unix::fs::PermissionsExt;
351
352 let secret_file = "/tmp/openai_secret";
353
354 if let Ok(metadata) = fs::metadata(secret_file) {
356 let permissions = metadata.permissions();
357 if permissions.mode() & 0o777 == 0o600 {
358 println!("7. Secret file has correct permissions (600)");
359 } else {
360 println!("7. Warning: Secret file permissions too open!");
361 }
362 }
363 }
364}