1use core::time::Duration;
4
5use base64ct::{Base64UrlUnpadded, Encoding};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone)]
11pub struct JsonWebToken {
12 pub header: Header,
14 pub claims: Claims,
16 pub signature: Vec<u8>,
18}
19impl JsonWebToken {
20 pub fn serialize(&self) -> String {
22 let header = self.header.encode();
23 let claims = self.claims.encode();
24 let signature = Base64UrlUnpadded::encode_string(&self.signature);
25
26 format!("{header}.{claims}.{signature}")
27 }
28
29 pub fn deserialize(value: &str) -> Option<Self> {
31 let mut parts = value.split(".");
32 let header = parts.next()?;
33 let claims = parts.next()?;
34 let signature = parts.next()?;
35
36 let header = serde_json::from_slice(&Base64UrlUnpadded::decode_vec(header).ok()?).ok()?;
37 let claims = serde_json::from_slice(&Base64UrlUnpadded::decode_vec(claims).ok()?).ok()?;
38 let signature = Base64UrlUnpadded::decode_vec(signature).ok()?;
39
40 Some(Self {
41 header,
42 claims,
43 signature,
44 })
45 }
46
47 pub fn message(&self) -> Vec<u8> {
49 Self::create_message(&self.header, &self.claims)
50 }
51
52 pub fn create_message(header: &Header, claims: &Claims) -> Vec<u8> {
54 format!("{}.{}", header.encode(), claims.encode()).into_bytes()
55 }
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct Header {
62 pub alg: String,
64
65 pub typ: String,
67
68 pub kid: String,
70}
71impl Header {
72 pub(crate) fn encode(&self) -> String {
77 let json = serde_json::to_vec(&self).expect("serializing the header should never fail");
78 Base64UrlUnpadded::encode_string(&json)
79 }
80}
81
82#[derive(Debug, Clone, Deserialize, Serialize)]
85pub struct Claims {
86 pub exp: u64,
88
89 pub iat: u64,
91
92 pub sub: String,
94
95 #[serde(flatten)]
97 pub typ: TokenType,
98}
99impl Claims {
100 pub(crate) fn encode(&self) -> String {
105 let json = serde_json::to_vec(&self).expect("serializing the claims should never fail");
106 Base64UrlUnpadded::encode_string(&json)
107 }
108
109 pub fn is_valid(&self) -> bool {
113 let exp = Duration::from_secs(self.exp);
114 let iat = Duration::from_secs(self.iat);
115 let Ok(now) = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) else {
116 return false;
117 };
118
119 exp > now && iat < now
120 }
121}
122
123#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
125#[serde(rename_all = "camelCase")]
126#[serde(tag = "typ")]
127#[non_exhaustive]
128pub enum TokenType {
129 Common,
131 Consent {
133 act: String,
135 },
136 Provisioning,
138}
139impl TokenType {
140 pub fn valid_for(&self) -> Duration {
142 match &self {
143 Self::Common => Duration::from_secs(60 * 60 * 24 * 30),
144 Self::Consent { .. } => Duration::from_secs(60 * 5),
145 Self::Provisioning => Duration::from_secs(60 * 60 * 4),
146 }
147 }
148}