tuwunel_core/config/
jwt.rs1use super::JwtConfig;
9use crate::{
10 Err, Error, Result, err, implement,
11 jwt::{Algorithm, DecodingKey, EncodingKey, errors::Error as JwtError},
12};
13
14#[derive(Clone, Copy)]
15pub(super) enum KeyFormat {
16 Hmac,
17 B64Hmac,
18 Ecdsa,
19 Eddsa,
20}
21
22const KEY_FORMATS: [(&str, KeyFormat); 5] = [
27 ("HMAC", KeyFormat::Hmac),
28 ("B64HMAC", KeyFormat::B64Hmac),
29 ("HMACB64", KeyFormat::B64Hmac),
30 ("ECDSA", KeyFormat::Ecdsa),
31 ("EDDSA", KeyFormat::Eddsa),
32];
33
34#[implement(JwtConfig)]
39pub fn decoding_key(&self) -> Result<DecodingKey> {
40 let key = self.key.as_str();
41
42 match self.key_format()? {
43 | KeyFormat::Hmac => Ok(DecodingKey::from_secret(key.as_bytes())),
44 | KeyFormat::B64Hmac =>
45 DecodingKey::from_base64_secret(key).map_err(invalid_key("base64")),
46 | KeyFormat::Ecdsa =>
47 DecodingKey::from_ec_pem(key.as_bytes()).map_err(invalid_key("ECDSA PEM")),
48 | KeyFormat::Eddsa =>
49 DecodingKey::from_ed_pem(key.as_bytes()).map_err(invalid_key("EDDSA PEM")),
50 }
51}
52
53#[implement(JwtConfig)]
58pub fn encoding_key(&self) -> Result<EncodingKey> {
59 let key = self.key.as_str();
60 let format = self.format.as_str();
61
62 match self.key_format()? {
63 | KeyFormat::Hmac => Ok(EncodingKey::from_secret(key.as_bytes())),
64 | KeyFormat::B64Hmac =>
65 EncodingKey::from_base64_secret(key).map_err(invalid_key("base64")),
66 | KeyFormat::Ecdsa | KeyFormat::Eddsa => Err!(Config(
67 "jwt.format",
68 "An {format} key is a public key; signing needs the HMAC or B64HMAC format."
69 )),
70 }
71}
72
73#[implement(JwtConfig)]
78pub fn algorithm(&self) -> Result<Algorithm> {
79 let algorithm = self.algorithm.as_str();
80
81 algorithm.parse().map_err(|e| {
82 err!(Config("jwt.algorithm", "JWT algorithm {algorithm:?} is not recognized: {e}"))
83 })
84}
85
86#[implement(JwtConfig)]
87pub(super) fn key_format(&self) -> Result<KeyFormat> {
88 let format = self.format.as_str();
89
90 KEY_FORMATS
91 .iter()
92 .find(|(name, _)| name.eq_ignore_ascii_case(format))
93 .map(|&(_, kind)| kind)
94 .ok_or_else(|| {
95 err!(Config(
96 "jwt.format",
97 "Key format {format:?} is not supported; use HMAC, B64HMAC, ECDSA or EDDSA."
98 ))
99 })
100}
101
102fn invalid_key(encoding: &'static str) -> impl FnOnce(JwtError) -> Error {
103 move |e| err!(Config("jwt.key", "JWT key is not valid {encoding}: {e}"))
104}