1pub mod json_file;
10
11use std::fmt;
12use std::future::Future;
13
14use serde::{Deserialize, Serialize};
15use webauthn_rs::prelude::{AuthenticationResult, Passkey};
16
17#[derive(Debug, Serialize, Deserialize, Clone)]
23#[non_exhaustive]
24pub struct AuthCode {
25 pub client_id: String,
26 pub redirect_uri: String,
27 pub code_challenge: String,
28 pub created_at: u64,
29}
30
31impl AuthCode {
32 #[must_use]
33 pub const fn new(
34 client_id: String,
35 redirect_uri: String,
36 code_challenge: String,
37 created_at: u64,
38 ) -> Self {
39 Self {
40 client_id,
41 redirect_uri,
42 code_challenge,
43 created_at,
44 }
45 }
46}
47
48#[derive(Debug, Serialize, Deserialize, Clone)]
50#[non_exhaustive]
51pub struct AccessTokenEntry {
52 pub client_id: String,
53 pub created_at: u64,
54 pub expires_in_secs: u64,
55 pub refresh_token: String,
56}
57
58impl AccessTokenEntry {
59 #[must_use]
60 pub const fn new(
61 client_id: String,
62 created_at: u64,
63 expires_in_secs: u64,
64 refresh_token: String,
65 ) -> Self {
66 Self {
67 client_id,
68 created_at,
69 expires_in_secs,
70 refresh_token,
71 }
72 }
73}
74
75#[derive(Debug, Serialize, Deserialize, Clone)]
77#[non_exhaustive]
78pub struct RefreshTokenEntry {
79 pub client_id: String,
80}
81
82impl RefreshTokenEntry {
83 #[must_use]
84 pub const fn new(client_id: String) -> Self {
85 Self { client_id }
86 }
87}
88
89#[derive(Serialize, Deserialize, Clone)]
91#[non_exhaustive]
92pub struct RegisteredClient {
93 pub client_secret: String,
94 pub redirect_uris: Vec<String>,
95}
96
97impl RegisteredClient {
98 #[must_use]
99 pub const fn new(client_secret: String, redirect_uris: Vec<String>) -> Self {
100 Self {
101 client_secret,
102 redirect_uris,
103 }
104 }
105}
106
107impl fmt::Debug for RegisteredClient {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 f.debug_struct("RegisteredClient")
111 .field("client_secret", &"[REDACTED]")
112 .field("redirect_uris", &self.redirect_uris)
113 .finish()
114 }
115}
116
117pub const TRANSIENT_STATE_TTL_SECS: u64 = 300;
123
124#[derive(Debug)]
130pub enum StoreError {
131 CapacityExceeded,
133 Backend(Box<dyn std::error::Error + Send + Sync>),
135}
136
137impl fmt::Display for StoreError {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match self {
140 Self::CapacityExceeded => write!(f, "store capacity exceeded"),
141 Self::Backend(e) => write!(f, "store backend error: {e}"),
142 }
143 }
144}
145
146impl std::error::Error for StoreError {
147 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
148 match self {
149 Self::Backend(e) => Some(&**e),
150 Self::CapacityExceeded => None,
151 }
152 }
153}
154
155pub trait TokenStore: Send + Sync + 'static {
161 fn store_auth_code(
163 &self,
164 code: String,
165 entry: AuthCode,
166 ) -> impl Future<Output = Result<(), StoreError>> + Send;
167
168 fn consume_auth_code(
170 &self,
171 code: &str,
172 ) -> impl Future<Output = Result<Option<AuthCode>, StoreError>> + Send;
173
174 fn store_access_token(
176 &self,
177 token: String,
178 entry: AccessTokenEntry,
179 ) -> impl Future<Output = Result<(), StoreError>> + Send;
180
181 fn get_access_token(
183 &self,
184 token: &str,
185 ) -> impl Future<Output = Result<Option<AccessTokenEntry>, StoreError>> + Send;
186
187 fn revoke_access_tokens_by_refresh(
189 &self,
190 refresh_token: &str,
191 ) -> impl Future<Output = Result<(), StoreError>> + Send;
192
193 fn store_refresh_token(
195 &self,
196 token: String,
197 entry: RefreshTokenEntry,
198 ) -> impl Future<Output = Result<(), StoreError>> + Send;
199
200 fn get_refresh_token(
202 &self,
203 token: &str,
204 ) -> impl Future<Output = Result<Option<RefreshTokenEntry>, StoreError>> + Send;
205
206 fn consume_refresh_token(
208 &self,
209 token: &str,
210 ) -> impl Future<Output = Result<Option<RefreshTokenEntry>, StoreError>> + Send;
211
212 fn cleanup_expired_tokens(
214 &self,
215 now: u64,
216 ) -> impl Future<Output = Result<(), StoreError>> + Send;
217}
218
219pub trait ClientStore: Send + Sync + 'static {
221 fn register_client(
223 &self,
224 id: String,
225 client: RegisteredClient,
226 ) -> impl Future<Output = Result<(), StoreError>> + Send;
227
228 fn try_register_client(
240 &self,
241 id: String,
242 client: RegisteredClient,
243 ) -> impl Future<Output = Result<bool, StoreError>> + Send;
244
245 fn get_client(
247 &self,
248 id: &str,
249 ) -> impl Future<Output = Result<Option<RegisteredClient>, StoreError>> + Send;
250
251 fn client_count(&self) -> impl Future<Output = Result<usize, StoreError>> + Send;
253}
254
255pub trait PasskeyStore: Send + Sync + 'static {
257 fn list_passkeys(&self) -> impl Future<Output = Result<Vec<Passkey>, StoreError>> + Send;
259
260 fn add_passkey_if_none(
266 &self,
267 passkey: Passkey,
268 ) -> impl Future<Output = Result<bool, StoreError>> + Send;
269
270 fn add_passkey(&self, passkey: Passkey) -> impl Future<Output = Result<(), StoreError>> + Send;
272
273 fn update_passkey(
275 &self,
276 auth_result: &AuthenticationResult,
277 ) -> impl Future<Output = Result<(), StoreError>> + Send;
278
279 fn has_passkeys(&self) -> impl Future<Output = Result<bool, StoreError>> + Send;
281}