turbomcp_auth/providers/
api_key.rs1use std::collections::HashMap;
6use std::sync::Arc;
7use std::time::SystemTime;
8
9use async_trait::async_trait;
10use tokio::sync::RwLock;
11
12use super::super::config::AuthProviderType;
13use super::super::types::{AuthContext, AuthCredentials, AuthProvider, TokenInfo, UserInfo};
14use turbomcp_protocol::{Error as McpError, Result as McpResult};
15
16#[derive(Debug)]
18pub struct ApiKeyProvider {
19 name: String,
21 api_keys: Arc<RwLock<HashMap<String, UserInfo>>>,
23}
24
25impl ApiKeyProvider {
26 #[must_use]
28 pub fn new(name: String) -> Self {
29 Self {
30 name,
31 api_keys: Arc::new(RwLock::new(HashMap::new())),
32 }
33 }
34
35 pub async fn add_api_key(&self, key: String, user_info: UserInfo) {
37 self.api_keys.write().await.insert(key, user_info);
38 }
39
40 pub async fn remove_api_key(&self, key: &str) -> bool {
42 self.api_keys.write().await.remove(key).is_some()
43 }
44
45 pub async fn list_api_keys(&self) -> Vec<String> {
47 self.api_keys.read().await.keys().cloned().collect()
48 }
49}
50
51#[async_trait]
52impl AuthProvider for ApiKeyProvider {
53 fn name(&self) -> &str {
54 &self.name
55 }
56
57 fn provider_type(&self) -> AuthProviderType {
58 AuthProviderType::ApiKey
59 }
60
61 async fn authenticate(&self, credentials: AuthCredentials) -> McpResult<AuthContext> {
62 match credentials {
63 AuthCredentials::ApiKey { key } => {
64 let api_keys = self.api_keys.read().await;
65 if let Some(user_info) = api_keys.get(&key) {
66 Ok(AuthContext {
67 user_id: user_info.id.clone(),
68 user: user_info.clone(),
69 roles: vec!["api_user".to_string()],
70 permissions: vec!["api_access".to_string()],
71 session_id: uuid::Uuid::new_v4().to_string(),
72 token: Some(TokenInfo {
73 access_token: key,
74 token_type: "ApiKey".to_string(),
75 refresh_token: None,
76 expires_in: None,
77 scope: None,
78 }),
79 provider: self.name.clone(),
80 authenticated_at: SystemTime::now(),
81 expires_at: None,
82 metadata: HashMap::new(),
83 })
84 } else {
85 Err(McpError::internal("Invalid API key".to_string()))
86 }
87 }
88 _ => Err(McpError::internal(
89 "Invalid credentials for API key provider".to_string(),
90 )),
91 }
92 }
93
94 async fn validate_token(&self, token: &str) -> McpResult<AuthContext> {
95 self.authenticate(AuthCredentials::ApiKey {
96 key: token.to_string(),
97 })
98 .await
99 }
100
101 async fn refresh_token(&self, _refresh_token: &str) -> McpResult<TokenInfo> {
102 Err(McpError::internal(
103 "API keys do not support token refresh".to_string(),
104 ))
105 }
106
107 async fn revoke_token(&self, token: &str) -> McpResult<()> {
108 let removed = self.remove_api_key(token).await;
109 if removed {
110 Ok(())
111 } else {
112 Err(McpError::internal("API key not found".to_string()))
113 }
114 }
115
116 async fn get_user_info(&self, token: &str) -> McpResult<UserInfo> {
117 let api_keys = self.api_keys.read().await;
118 api_keys
119 .get(token)
120 .cloned()
121 .ok_or_else(|| McpError::internal("Invalid API key".to_string()))
122 }
123}