turbomcp_auth/providers/
api_key.rs

1//! API Key Authentication Provider
2//!
3//! Simple API key-based authentication for service-to-service communication.
4
5use 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/// API Key authentication provider
17#[derive(Debug)]
18pub struct ApiKeyProvider {
19    /// Provider name
20    name: String,
21    /// Valid API keys with associated user info
22    api_keys: Arc<RwLock<HashMap<String, UserInfo>>>,
23}
24
25impl ApiKeyProvider {
26    /// Create a new API key provider
27    #[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    /// Add an API key
36    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    /// Remove an API key
41    pub async fn remove_api_key(&self, key: &str) -> bool {
42        self.api_keys.write().await.remove(key).is_some()
43    }
44
45    /// List all API keys (returns keys only, not full info for security)
46    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}