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