Skip to main content

systemprompt_agent/services/shared/
auth.rs

1use crate::services::shared::error::{AgentServiceError, Result};
2use jsonwebtoken::{decode, DecodingKey, Validation};
3pub use systemprompt_models::auth::JwtClaims;
4use systemprompt_traits::AgentJwtClaims;
5
6pub struct JwtValidator {
7    decoding_key: DecodingKey,
8    validation: Validation,
9}
10
11impl std::fmt::Debug for JwtValidator {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        f.debug_struct("JwtValidator")
14            .field("validation", &self.validation)
15            .field("decoding_key", &"<decoding_key>")
16            .finish()
17    }
18}
19
20impl JwtValidator {
21    pub fn new(secret: String) -> Self {
22        Self {
23            decoding_key: DecodingKey::from_secret(secret.as_ref()),
24            validation: Validation::default(),
25        }
26    }
27
28    pub fn validate_token(&self, token: &str) -> Result<JwtClaims> {
29        decode::<JwtClaims>(token, &self.decoding_key, &self.validation)
30            .map(|data| data.claims)
31            .map_err(|e| AgentServiceError::Authentication(format!("invalid token: {e}")))
32    }
33}
34
35pub fn extract_bearer_token(authorization_header: &str) -> Result<&str> {
36    authorization_header.strip_prefix("Bearer ").ok_or_else(|| {
37        AgentServiceError::Authentication("invalid authorization header format".to_string())
38    })
39}
40
41#[derive(Debug, Clone)]
42pub struct AgentSessionUser {
43    pub id: String,
44    pub username: String,
45    pub user_type: String,
46    pub roles: Vec<String>,
47}
48
49impl AgentSessionUser {
50    pub fn from_jwt_claims(claims: AgentJwtClaims) -> Self {
51        Self {
52            id: claims.subject,
53            username: claims.username,
54            user_type: claims.user_type,
55            roles: claims.permissions,
56        }
57    }
58}
59
60impl From<JwtClaims> for AgentSessionUser {
61    fn from(claims: JwtClaims) -> Self {
62        Self {
63            id: claims.sub.clone(),
64            username: claims.username.clone(),
65            user_type: claims.user_type.to_string(),
66            roles: claims.get_scopes(),
67        }
68    }
69}