Skip to main content

web/
token.rs

1use base64::{Engine as _, engine::general_purpose};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Serialize, Deserialize)]
6pub struct TokenDetails {
7    pub token: Option<String>,
8    pub token_uuid: uuid::Uuid,
9    pub user_id: uuid::Uuid,
10    pub expires_in: Option<i64>,
11}
12
13#[derive(Debug, Serialize, Deserialize, Clone)]
14pub struct TokenClaims {
15    pub sub: String,
16    pub token_uuid: String,
17    pub exp: i64,
18    pub iat: i64,
19    pub nbf: i64,
20}
21
22pub fn generate_jwt_token(
23    user_id: uuid::Uuid,
24    ttl: i64,
25    private_key: &str,
26) -> Result<TokenDetails, jsonwebtoken::errors::Error> {
27    generate_jwt_token_with_uuid(user_id, Uuid::new_v4(), ttl, private_key)
28}
29
30pub fn generate_jwt_token_with_uuid(
31    user_id: uuid::Uuid,
32    token_uuid: uuid::Uuid,
33    ttl: i64,
34    private_key: &str,
35) -> Result<TokenDetails, jsonwebtoken::errors::Error> {
36    let bytes_private_key = general_purpose::STANDARD.decode(private_key).unwrap();
37    let decoded_private_key = String::from_utf8(bytes_private_key).unwrap();
38
39    let now = chrono::Utc::now();
40    let mut token_details = TokenDetails {
41        user_id,
42        token_uuid,
43        expires_in: Some((now + chrono::Duration::minutes(ttl)).timestamp()),
44        token: None,
45    };
46
47    let claims = TokenClaims {
48        sub: token_details.user_id.to_string(),
49        token_uuid: token_details.token_uuid.to_string(),
50        exp: token_details.expires_in.unwrap(),
51        iat: now.timestamp(),
52        nbf: now.timestamp(),
53    };
54
55    let header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::RS256);
56    let token = jsonwebtoken::encode(
57        &header,
58        &claims,
59        &jsonwebtoken::EncodingKey::from_rsa_pem(decoded_private_key.as_bytes())?,
60    )?;
61    token_details.token = Some(token);
62    Ok(token_details)
63}
64
65pub fn verify_jwt_token(
66    public_key: &str,
67    token: &str,
68) -> Result<TokenDetails, jsonwebtoken::errors::Error> {
69    let bytes_public_key = general_purpose::STANDARD.decode(public_key).unwrap();
70    let decoded_public_key = String::from_utf8(bytes_public_key).unwrap();
71
72    let validation = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::RS256);
73
74    let decoded = jsonwebtoken::decode::<TokenClaims>(
75        token,
76        &jsonwebtoken::DecodingKey::from_rsa_pem(decoded_public_key.as_bytes())?,
77        &validation,
78    )?;
79
80    let user_id = Uuid::parse_str(decoded.claims.sub.as_str()).unwrap();
81    let token_uuid = Uuid::parse_str(decoded.claims.token_uuid.as_str()).unwrap();
82
83    Ok(TokenDetails {
84        token: None,
85        token_uuid,
86        user_id,
87        expires_in: None,
88    })
89}