github_mcp/auth/strategies/
pat.rs1use async_trait::async_trait;
4
5use super::super::auth_strategy::{AuthConfig, AuthStrategy, Credentials};
6use super::super::errors::AuthError;
7
8#[derive(Debug, Default)]
9pub struct PatAuthStrategy;
10
11#[async_trait]
12impl AuthStrategy for PatAuthStrategy {
13 async fn authenticate(&self, config: &AuthConfig) -> anyhow::Result<Credentials> {
14 let token = config
15 .get("token")
16 .ok_or_else(|| AuthError::MissingCredentials("token".to_string()))?;
17
18 let mut credentials = Credentials::new();
19 credentials.insert("token".to_string(), token.clone());
20 credentials.insert(
21 "authorization_header".to_string(),
22 format!("Bearer {token}"),
23 );
24 Ok(credentials)
25 }
26
27 fn validate_credentials(&self, credentials: &Credentials) -> bool {
28 credentials
29 .get("token")
30 .is_some_and(|token| !token.is_empty())
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[tokio::test]
39 async fn wraps_the_token_in_a_bearer_authorization_header() {
40 let strategy = PatAuthStrategy;
41 let config = AuthConfig::from([("token".to_string(), "abc123".to_string())]);
42 let credentials = strategy.authenticate(&config).await.unwrap();
43 assert_eq!(
44 credentials.get("authorization_header").unwrap(),
45 "Bearer abc123"
46 );
47 }
48
49 #[tokio::test]
50 async fn rejects_a_config_missing_the_token() {
51 let strategy = PatAuthStrategy;
52 assert!(strategy.authenticate(&AuthConfig::new()).await.is_err());
53 }
54}