Skip to main content

tuwunel_admin/debug/
create_jwt.rs

1use 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}