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<i64>,
27 #[serde(skip_serializing_if = "Option::is_none")]
29 pub expires_at: Option<i64>,
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<i64>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 expires_at: Option<i64>,
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() -> i64,
66}
67
68fn default_now() -> fn() -> i64 {
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 if let Some(e) = params.expires_in {
114 if e < 0 {
115 tokenset.expires_in = Some(0);
116 }
117 }
118
119 tokenset
120 }
121
122 pub fn expired(&self) -> bool {
124 let expires_in = self.get_expires_in_internal();
125
126 if let Some(e) = expires_in {
127 return e == 0;
128 }
129 false
130 }
131
132 pub fn claims(&self) -> Option<HashMap<String, Value>> {
135 if let Some(id_token) = &self.id_token {
136 let id_token_components: Vec<&str> = id_token.split('.').collect();
137 let payload = id_token_components.get(1)?;
138
139 return match base64_url::decode(payload) {
140 Ok(decoded) => serde_json::from_slice::<HashMap<String, Value>>(&decoded).ok(),
141 Err(_) => None,
142 };
143 }
144 None
145 }
146
147 pub fn get_access_token(&self) -> Option<String> {
149 self.access_token.clone()
150 }
151
152 pub fn get_token_type(&self) -> Option<String> {
154 self.token_type.clone()
155 }
156
157 pub fn get_id_token(&self) -> Option<String> {
159 self.id_token.clone()
160 }
161
162 pub fn get_refresh_token(&self) -> Option<String> {
164 self.refresh_token.clone()
165 }
166
167 pub fn get_expires_in(&self) -> Option<i64> {
169 self.expires_in
170 }
171
172 pub fn get_expires_at(&self) -> Option<i64> {
174 self.expires_at
175 }
176
177 pub fn get_session_state(&self) -> Option<String> {
179 self.session_state.clone()
180 }
181
182 pub fn get_scope(&self) -> Option<String> {
184 self.scope.clone()
185 }
186
187 pub fn get_other(&self) -> Option<HashMap<String, Value>> {
189 self.other.clone()
190 }
191
192 pub(self) fn get_expires_in_internal(&self) -> Option<i64> {
193 if let Some(e) = self.expires_at {
194 return Some(max((Wrapping(e) - Wrapping((self.now)())).0, 0));
195 }
196 None
197 }
198
199 pub(crate) fn set_id_token(&mut self, token: Option<String>) {
201 self.id_token = token;
202 }
203
204 pub(crate) fn set_session_state(&mut self, session_state: Option<String>) {
206 self.session_state = session_state;
207 }
208}
209
210#[cfg(test)]
211#[path = "./tests/tokenset_tests.rs"]
212mod tokenset_tests;