Skip to main content

systemprompt_traits/
jwt.rs

1use std::sync::Arc;
2use systemprompt_identifiers::SessionId;
3
4pub type JwtResult<T> = Result<T, JwtProviderError>;
5
6#[derive(Debug, thiserror::Error)]
7#[non_exhaustive]
8pub enum JwtProviderError {
9    #[error("Invalid token")]
10    InvalidToken,
11
12    #[error("Token expired")]
13    TokenExpired,
14
15    #[error("Missing audience: {0}")]
16    MissingAudience(String),
17
18    #[error("Configuration error: {0}")]
19    ConfigurationError(String),
20
21    #[error("Internal error: {0}")]
22    Internal(String),
23}
24
25impl From<anyhow::Error> for JwtProviderError {
26    fn from(err: anyhow::Error) -> Self {
27        Self::Internal(err.to_string())
28    }
29}
30
31#[derive(Debug, Clone)]
32pub struct AgentJwtClaims {
33    pub subject: String,
34    pub username: String,
35    pub user_type: String,
36    pub audiences: Vec<String>,
37    pub permissions: Vec<String>,
38    pub is_admin: bool,
39    pub expires_at: i64,
40    pub issued_at: i64,
41}
42
43impl AgentJwtClaims {
44    #[must_use]
45    pub fn has_audience(&self, audience: &str) -> bool {
46        self.audiences.iter().any(|a| a == audience)
47    }
48
49    #[must_use]
50    pub fn has_permission(&self, permission: &str) -> bool {
51        self.permissions.iter().any(|p| p == permission)
52    }
53}
54
55#[derive(Debug, Clone)]
56pub struct GenerateTokenParams {
57    pub user_id: String,
58    pub username: String,
59    pub user_type: String,
60    pub permissions: Vec<String>,
61    pub audiences: Vec<String>,
62    pub session_id: SessionId,
63    pub expires_in_hours: Option<u32>,
64}
65
66impl GenerateTokenParams {
67    #[must_use]
68    pub fn new(
69        user_id: impl Into<String>,
70        username: impl Into<String>,
71        session_id: SessionId,
72    ) -> Self {
73        Self {
74            user_id: user_id.into(),
75            username: username.into(),
76            user_type: "user".to_string(),
77            permissions: Vec::new(),
78            audiences: Vec::new(),
79            session_id,
80            expires_in_hours: None,
81        }
82    }
83
84    #[must_use]
85    pub fn with_user_type(mut self, user_type: impl Into<String>) -> Self {
86        self.user_type = user_type.into();
87        self
88    }
89
90    #[must_use]
91    pub fn with_permissions(mut self, permissions: Vec<String>) -> Self {
92        self.permissions = permissions;
93        self
94    }
95
96    #[must_use]
97    pub fn with_audiences(mut self, audiences: Vec<String>) -> Self {
98        self.audiences = audiences;
99        self
100    }
101
102    #[must_use]
103    pub const fn with_expires_in_hours(mut self, hours: u32) -> Self {
104        self.expires_in_hours = Some(hours);
105        self
106    }
107}
108
109pub trait JwtValidationProvider: Send + Sync {
110    fn validate_token(&self, token: &str) -> JwtResult<AgentJwtClaims>;
111
112    fn generate_token(&self, params: GenerateTokenParams) -> JwtResult<String>;
113
114    fn generate_secure_token(&self, prefix: &str) -> String;
115}
116
117pub type DynJwtValidationProvider = Arc<dyn JwtValidationProvider>;