turbomcp_auth/providers/
api_key.rs1use std::collections::HashMap;
6use std::sync::Arc;
7
8use async_trait::async_trait;
9use tokio::sync::RwLock;
10
11use super::super::config::AuthProviderType;
12use super::super::context::AuthContext;
13use super::super::types::{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 let token = TokenInfo {
67 access_token: key,
68 token_type: "ApiKey".to_string(),
69 refresh_token: None,
70 expires_in: None,
71 scope: None,
72 };
73
74 AuthContext::builder()
75 .subject(user_info.id.clone())
76 .user(user_info.clone())
77 .roles(vec!["api_user".to_string()])
78 .permissions(vec!["api_access".to_string()])
79 .request_id(uuid::Uuid::new_v4().to_string())
80 .token(token)
81 .provider(self.name.clone())
82 .build()
83 .map_err(|e| McpError::internal(e.to_string()))
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}