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