support_kit/encryption/
token_control.rs

1use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
2use rand::Rng;
3use secrecy::{ExposeSecret, SecretString};
4
5use crate::{AuthTokenGenerationFailure, AuthTokenVerificationFailure, Configuration, TokenError};
6
7/// The claims that our json web token can make.
8#[derive(serde::Deserialize, serde::Serialize)]
9pub struct TokenContents {
10    /// The expected subject of the token. This is the user's ID.
11    pub sub: String,
12    /// The expected expiration of the token.
13    pub exp: usize,
14}
15
16pub struct TokenControl(pub Configuration);
17
18impl TokenControl {
19    pub fn from_config(config: Configuration) -> Self {
20        Self(config)
21    }
22
23    pub fn auth_token(&self, id: uuid::Uuid) -> crate::Result<String> {
24        let secret = self.0.secret.clone();
25
26        Ok(generate_auth_token(&id, &secret)?)
27    }
28
29    pub fn validate_auth_token(&self, token: String) -> crate::Result<uuid::Uuid> {
30        let secret = self.0.secret.clone();
31
32        Ok(validate_auth_token(token, &secret)?)
33    }
34
35    pub fn random(&self) -> String {
36        generate_randomized_token()
37    }
38}
39
40/// Generate a JSON web token for auth.
41#[tracing::instrument(name = "Generating session auth token", skip(id, secret))]
42pub fn generate_auth_token(id: &uuid::Uuid, secret: &SecretString) -> Result<String, TokenError> {
43    let header = Header {
44        kid: Some(secret.expose_secret().to_owned()),
45        alg: Algorithm::HS512,
46        ..Default::default()
47    };
48
49    let claim = TokenContents {
50        sub: id.to_string(),
51        exp: 10000000000,
52    };
53
54    Ok(encode(
55        &header,
56        &claim,
57        &EncodingKey::from_secret(secret.expose_secret().as_bytes()),
58    )
59    .map_err(AuthTokenGenerationFailure::from)?)
60}
61
62/// Validate a JSON web token.
63#[tracing::instrument(
64    level = "debug",
65    name = "Validate session auth token",
66    skip(token, secret)
67)]
68pub fn validate_auth_token(token: String, secret: &SecretString) -> Result<uuid::Uuid, TokenError> {
69    let raw_token = decode::<TokenContents>(
70        &token,
71        &DecodingKey::from_secret(secret.expose_secret().as_bytes()),
72        &Validation::new(jsonwebtoken::Algorithm::HS512),
73    )
74    .map_err(AuthTokenVerificationFailure::from)?
75    .claims
76    .sub;
77
78    Ok(uuid::Uuid::parse_str(&raw_token)?)
79}
80
81/// Generates a random token for use in session tokens.
82pub fn generate_randomized_token() -> String {
83    let mut rng = rand::thread_rng();
84
85    std::iter::repeat_with(|| rng.sample(rand::distributions::Alphanumeric))
86        .map(char::from)
87        .take(25)
88        .collect()
89}