turbomcp_auth/providers/
api_key.rs1use std::collections::HashMap;
11use std::sync::Arc;
12
13use async_trait::async_trait;
14use tokio::sync::RwLock;
15
16use super::super::api_key_validation::validate_api_key;
17use super::super::config::AuthProviderType;
18use super::super::context::AuthContext;
19use super::super::types::{AuthCredentials, AuthProvider, TokenInfo, UserInfo};
20use turbomcp_protocol::{Error as McpError, Result as McpResult};
21
22#[derive(Debug)]
24pub struct ApiKeyProvider {
25 name: String,
27 api_keys: Arc<RwLock<HashMap<String, UserInfo>>>,
29}
30
31impl ApiKeyProvider {
32 #[must_use]
34 pub fn new(name: String) -> Self {
35 Self {
36 name,
37 api_keys: Arc::new(RwLock::new(HashMap::new())),
38 }
39 }
40
41 pub async fn add_api_key(&self, key: String, user_info: UserInfo) {
43 self.api_keys.write().await.insert(key, user_info);
44 }
45
46 pub async fn remove_api_key(&self, key: &str) -> bool {
48 self.api_keys.write().await.remove(key).is_some()
49 }
50
51 pub async fn list_api_keys(&self) -> Vec<String> {
53 self.api_keys.read().await.keys().cloned().collect()
54 }
55}
56
57#[async_trait]
58impl AuthProvider for ApiKeyProvider {
59 fn name(&self) -> &str {
60 &self.name
61 }
62
63 fn provider_type(&self) -> AuthProviderType {
64 AuthProviderType::ApiKey
65 }
66
67 async fn authenticate(&self, credentials: AuthCredentials) -> McpResult<AuthContext> {
68 match credentials {
69 AuthCredentials::ApiKey { key } => {
70 let api_keys = self.api_keys.read().await;
71
72 let mut matched_user_info: Option<UserInfo> = None;
76
77 for (stored_key, user_info) in api_keys.iter() {
78 if validate_api_key(&key, stored_key) {
79 matched_user_info = Some(user_info.clone());
80 break;
81 }
82 }
83
84 if let Some(user_info) = matched_user_info {
85 let token = TokenInfo {
86 access_token: key,
87 token_type: "ApiKey".to_string(),
88 refresh_token: None,
89 expires_in: None,
90 scope: None,
91 };
92
93 AuthContext::builder()
94 .subject(user_info.id.clone())
95 .user(user_info.clone())
96 .roles(vec!["api_user".to_string()])
97 .permissions(vec!["api_access".to_string()])
98 .request_id(uuid::Uuid::new_v4().to_string())
99 .token(token)
100 .provider(self.name.clone())
101 .build()
102 .map_err(|e| McpError::internal(e.to_string()))
103 } else {
104 Err(McpError::internal("Invalid API key".to_string()))
105 }
106 }
107 _ => Err(McpError::internal(
108 "Invalid credentials for API key provider".to_string(),
109 )),
110 }
111 }
112
113 async fn validate_token(&self, token: &str) -> McpResult<AuthContext> {
114 self.authenticate(AuthCredentials::ApiKey {
115 key: token.to_string(),
116 })
117 .await
118 }
119
120 async fn refresh_token(&self, _refresh_token: &str) -> McpResult<TokenInfo> {
121 Err(McpError::internal(
122 "API keys do not support token refresh".to_string(),
123 ))
124 }
125
126 async fn revoke_token(&self, token: &str) -> McpResult<()> {
127 let removed = self.remove_api_key(token).await;
128 if removed {
129 Ok(())
130 } else {
131 Err(McpError::internal("API key not found".to_string()))
132 }
133 }
134
135 async fn get_user_info(&self, token: &str) -> McpResult<UserInfo> {
136 let api_keys = self.api_keys.read().await;
137
138 for (stored_key, user_info) in api_keys.iter() {
140 if validate_api_key(token, stored_key) {
141 return Ok(user_info.clone());
142 }
143 }
144
145 Err(McpError::internal("Invalid API key".to_string()))
146 }
147}