tuwunel_admin/debug/
create_jwt.rs1use std::str::FromStr;
2
3use serde::Serialize;
4use tuwunel_core::{
5 Err, Result, err,
6 jwt::{Algorithm, EncodingKey, Header, encode},
7 utils::time::now_secs,
8};
9
10use crate::admin_command;
11
12#[admin_command]
13pub(super) async fn create_jwt(
14 &self,
15 user: String,
16 exp_from_now: Option<u64>,
17 nbf_from_now: Option<u64>,
18 issuer: Option<String>,
19 audience: Option<String>,
20) -> Result {
21 #[derive(Serialize)]
22 struct Claim {
23 sub: String,
24 iss: Option<String>,
25 aud: Option<String>,
26 exp: Option<usize>,
27 nbf: Option<usize>,
28 }
29
30 let config = &self.services.config.jwt;
31 if config.format.as_str() != "HMAC" {
32 return Err!("This command only supports HMAC key format, not {}.", config.format);
33 }
34
35 let key = EncodingKey::from_secret(config.key.as_ref());
36 let alg = Algorithm::from_str(config.algorithm.as_str()).map_err(|e| {
37 err!(Config("jwt.algorithm", "JWT algorithm is not recognized or configured {e}"))
38 })?;
39
40 let header = Header { alg, ..Default::default() };
41 let claim = Claim {
42 sub: user,
43
44 iss: issuer,
45
46 aud: audience,
47
48 exp: exp_from_now
49 .and_then(|val| now_secs().checked_add(val))
50 .map(TryInto::try_into)
51 .and_then(Result::ok),
52
53 nbf: nbf_from_now
54 .and_then(|val| now_secs().checked_add(val))
55 .map(TryInto::try_into)
56 .and_then(Result::ok),
57 };
58
59 encode(&header, &claim, &key)
60 .map_err(|e| err!("Failed to encode JWT: {e}"))
61 .map(async |token| self.write_str(&token).await)?
62 .await
63}