openid_client/
tokenset.rs1use std::{cmp::max, collections::HashMap, num::Wrapping};
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::helpers::now;
7
8#[derive(Debug, Default, Serialize, Deserialize)]
11pub struct TokenSetParams {
12 #[serde(skip_serializing_if = "Option::is_none")]
14 pub access_token: Option<String>,
15 #[serde(skip_serializing_if = "Option::is_none")]
17 pub token_type: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub id_token: Option<String>,
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub refresh_token: Option<String>,
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub expires_in: Option<u64>,
27 #[serde(skip_serializing_if = "Option::is_none")]
29 pub expires_at: Option<u64>,
30 #[serde(skip_serializing_if = "Option::is_none")]
32 pub session_state: Option<String>,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub scope: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub other: Option<HashMap<String, Value>>,
39}
40
41#[derive(Debug, Serialize, Deserialize, Clone)]
45pub struct TokenSet {
46 #[serde(skip_serializing_if = "Option::is_none")]
47 access_token: Option<String>,
48 #[serde(skip_serializing_if = "Option::is_none")]
49 token_type: Option<String>,
50 #[serde(skip_serializing_if = "Option::is_none")]
51 id_token: Option<String>,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 refresh_token: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 expires_in: Option<u64>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 expires_at: Option<u64>,
58 #[serde(skip_serializing_if = "Option::is_none")]
59 session_state: Option<String>,
60 #[serde(skip_serializing_if = "Option::is_none")]
61 scope: Option<String>,
62 #[serde(skip_serializing_if = "Option::is_none", flatten)]
63 other: Option<HashMap<String, Value>>,
64 #[serde(skip_serializing, skip_deserializing, default = "default_now")]
65 pub(crate) now: fn() -> u64,
66}
67
68fn default_now() -> fn() -> u64 {
69 now
70}
71
72impl Default for TokenSet {
73 fn default() -> Self {
74 Self {
75 access_token: Default::default(),
76 token_type: Default::default(),
77 id_token: Default::default(),
78 refresh_token: Default::default(),
79 expires_in: Default::default(),
80 expires_at: Default::default(),
81 session_state: Default::default(),
82 scope: Default::default(),
83 other: Default::default(),
84 now,
85 }
86 }
87}
88
89impl TokenSet {
90 pub fn new(params: TokenSetParams) -> Self {
94 let mut tokenset = Self {
95 access_token: params.access_token,
96 token_type: params.token_type,
97 id_token: params.id_token,
98 refresh_token: params.refresh_token,
99 expires_in: params.expires_in,
100 expires_at: params.expires_at,
101 session_state: params.session_state,
102 scope: params.scope,
103 other: params.other,
104 now,
105 };
106
107 if params.expires_at.is_none() && params.expires_in.is_some() {
108 if let Some(e) = params.expires_in {
109 tokenset.expires_at = Some((Wrapping((tokenset.now)()) + Wrapping(e)).0);
110 }
111 }
112
113 tokenset
114 }
115
116 pub fn expired(&self) -> bool {
118 let expires_in = self.get_expires_in_internal();
119
120 if let Some(e) = expires_in {
121 return e == 0;
122 }
123 false
124 }
125
126 pub fn claims(&self) -> Option<HashMap<String, Value>> {
129 if let Some(id_token) = &self.id_token {
130 let id_token_components: Vec<&str> = id_token.split('.').collect();
131 let payload = id_token_components.get(1)?;
132
133 return match base64_url::decode(payload) {
134 Ok(decoded) => serde_json::from_slice::<HashMap<String, Value>>(&decoded).ok(),
135 Err(_) => None,
136 };
137 }
138 None
139 }
140
141 pub fn get_access_token(&self) -> Option<String> {
143 self.access_token.clone()
144 }
145
146 pub fn get_token_type(&self) -> Option<String> {
148 self.token_type.clone()
149 }
150
151 pub fn get_id_token(&self) -> Option<String> {
153 self.id_token.clone()
154 }
155
156 pub fn get_refresh_token(&self) -> Option<String> {
158 self.refresh_token.clone()
159 }
160
161 pub fn get_expires_in(&self) -> Option<u64> {
163 self.expires_in
164 }
165
166 pub fn get_expires_at(&self) -> Option<u64> {
168 self.expires_at
169 }
170
171 pub fn get_session_state(&self) -> Option<String> {
173 self.session_state.clone()
174 }
175
176 pub fn get_scope(&self) -> Option<String> {
178 self.scope.clone()
179 }
180
181 pub fn get_other(&self) -> Option<HashMap<String, Value>> {
183 self.other.clone()
184 }
185
186 pub(self) fn get_expires_in_internal(&self) -> Option<u64> {
187 if let Some(e) = self.expires_at {
188 return Some(max((Wrapping(e) - Wrapping((self.now)())).0, 0));
189 }
190 None
191 }
192
193 pub(crate) fn set_id_token(&mut self, token: Option<String>) {
195 self.id_token = token;
196 }
197
198 pub(crate) fn set_session_state(&mut self, session_state: Option<String>) {
200 self.session_state = session_state;
201 }
202}
203
204#[cfg(test)]
205#[path = "./tests/tokenset_tests.rs"]
206mod tokenset_tests;