Skip to main content

systemprompt_security/session/
generator.rs

1use chrono::{Duration, Utc};
2use jsonwebtoken::{Algorithm, Header, encode};
3use systemprompt_identifiers::{SessionId, SessionToken, UserId};
4use systemprompt_models::auth::{
5    JwtAudience, JwtClaims, Permission, RateLimitTier, TokenType, UserType,
6};
7
8use crate::error::{JwtError, JwtResult};
9use crate::keys::authority;
10
11#[derive(Debug)]
12pub struct SessionParams<'a> {
13    pub user_id: &'a UserId,
14    pub session_id: &'a SessionId,
15    pub email: &'a str,
16    pub duration: Duration,
17    pub user_type: UserType,
18    pub permissions: Vec<Permission>,
19    pub roles: Vec<String>,
20    pub department: Option<String>,
21    pub rate_limit_tier: RateLimitTier,
22}
23
24#[derive(Debug)]
25pub struct SessionGenerator {
26    issuer: String,
27}
28
29impl SessionGenerator {
30    pub fn new(issuer: impl Into<String>) -> Self {
31        Self {
32            issuer: issuer.into(),
33        }
34    }
35
36    pub fn generate(&self, params: &SessionParams<'_>) -> JwtResult<SessionToken> {
37        let now = Utc::now();
38        let expiry = now + params.duration;
39
40        let claims = JwtClaims {
41            sub: params.user_id.to_string(),
42            iat: now.timestamp(),
43            exp: expiry.timestamp(),
44            nbf: Some(now.timestamp()),
45            iss: self.issuer.clone(),
46            aud: JwtAudience::standard(),
47            jti: uuid::Uuid::new_v4().to_string(),
48            scope: params.permissions.clone(),
49            username: params.email.to_owned(),
50            email: params.email.to_owned(),
51            user_type: params.user_type,
52            roles: params.roles.clone(),
53            department: params.department.clone(),
54            client_id: None,
55            token_type: TokenType::Bearer,
56            auth_time: now.timestamp(),
57            session_id: Some(params.session_id.clone()),
58            rate_limit_tier: Some(params.rate_limit_tier),
59            plugin_id: None,
60            act: None,
61        };
62
63        let kid = authority::active_kid().map_err(|e| JwtError::Signing(e.to_string()))?;
64        let mut header = Header::new(Algorithm::RS256);
65        header.kid = Some(kid.to_owned());
66        let key = authority::encoding_key().map_err(|e| JwtError::Signing(e.to_string()))?;
67        let token = encode(&header, &claims, key).map_err(JwtError::from)?;
68
69        Ok(SessionToken::new(token))
70    }
71}