mas_storage/oauth2/access_token.rs
1// Copyright 2024 New Vector Ltd.
2// Copyright 2021-2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7use async_trait::async_trait;
8use chrono::Duration;
9use mas_data_model::{AccessToken, Session};
10use rand_core::RngCore;
11use ulid::Ulid;
12
13use crate::{Clock, repository_impl};
14
15/// An [`OAuth2AccessTokenRepository`] helps interacting with [`AccessToken`]
16/// saved in the storage backend
17#[async_trait]
18pub trait OAuth2AccessTokenRepository: Send + Sync {
19 /// The error type returned by the repository
20 type Error;
21
22 /// Lookup an access token by its ID
23 ///
24 /// Returns the access token if it exists, `None` otherwise
25 ///
26 /// # Parameters
27 ///
28 /// * `id`: The ID of the access token to lookup
29 ///
30 /// # Errors
31 ///
32 /// Returns [`Self::Error`] if the underlying repository fails
33 async fn lookup(&mut self, id: Ulid) -> Result<Option<AccessToken>, Self::Error>;
34
35 /// Find an access token by its token
36 ///
37 /// Returns the access token if it exists, `None` otherwise
38 ///
39 /// # Parameters
40 ///
41 /// * `access_token`: The token of the access token to lookup
42 ///
43 /// # Errors
44 ///
45 /// Returns [`Self::Error`] if the underlying repository fails
46 async fn find_by_token(
47 &mut self,
48 access_token: &str,
49 ) -> Result<Option<AccessToken>, Self::Error>;
50
51 /// Add a new access token to the database
52 ///
53 /// Returns the newly created access token
54 ///
55 /// # Parameters
56 ///
57 /// * `rng`: A random number generator
58 /// * `clock`: The clock used to generate timestamps
59 /// * `session`: The session the access token is associated with
60 /// * `access_token`: The access token to add
61 /// * `expires_after`: The duration after which the access token expires. If
62 /// [`None`] the access token never expires
63 ///
64 /// # Errors
65 ///
66 /// Returns [`Self::Error`] if the underlying repository fails
67 async fn add(
68 &mut self,
69 rng: &mut (dyn RngCore + Send),
70 clock: &dyn Clock,
71 session: &Session,
72 access_token: String,
73 expires_after: Option<Duration>,
74 ) -> Result<AccessToken, Self::Error>;
75
76 /// Revoke an access token
77 ///
78 /// Returns the revoked access token
79 ///
80 /// # Parameters
81 ///
82 /// * `clock`: The clock used to generate timestamps
83 /// * `access_token`: The access token to revoke
84 ///
85 /// # Errors
86 ///
87 /// Returns [`Self::Error`] if the underlying repository fails
88 async fn revoke(
89 &mut self,
90 clock: &dyn Clock,
91 access_token: AccessToken,
92 ) -> Result<AccessToken, Self::Error>;
93
94 /// Mark the access token as used, to track when it was first used
95 ///
96 /// # Parameters
97 ///
98 /// * `clock`: The clock used to generate timestamps
99 /// * `access_token`: The access token to mark as used
100 ///
101 /// # Errors
102 ///
103 /// Returns [`Self::Error`] if the underlying repository fails
104 async fn mark_used(
105 &mut self,
106 clock: &dyn Clock,
107 access_token: AccessToken,
108 ) -> Result<AccessToken, Self::Error>;
109
110 /// Cleanup revoked access tokens
111 ///
112 /// Returns the number of access tokens that were cleaned up
113 ///
114 /// # Parameters
115 ///
116 /// * `clock`: The clock used to get the current time
117 ///
118 /// # Errors
119 ///
120 /// Returns [`Self::Error`] if the underlying repository fails
121 async fn cleanup_revoked(&mut self, clock: &dyn Clock) -> Result<usize, Self::Error>;
122}
123
124repository_impl!(OAuth2AccessTokenRepository:
125 async fn lookup(&mut self, id: Ulid) -> Result<Option<AccessToken>, Self::Error>;
126
127 async fn find_by_token(
128 &mut self,
129 access_token: &str,
130 ) -> Result<Option<AccessToken>, Self::Error>;
131
132 async fn add(
133 &mut self,
134 rng: &mut (dyn RngCore + Send),
135 clock: &dyn Clock,
136 session: &Session,
137 access_token: String,
138 expires_after: Option<Duration>,
139 ) -> Result<AccessToken, Self::Error>;
140
141 async fn revoke(
142 &mut self,
143 clock: &dyn Clock,
144 access_token: AccessToken,
145 ) -> Result<AccessToken, Self::Error>;
146
147 async fn mark_used(
148 &mut self,
149 clock: &dyn Clock,
150 access_token: AccessToken,
151 ) -> Result<AccessToken, Self::Error>;
152
153 async fn cleanup_revoked(&mut self, clock: &dyn Clock) -> Result<usize, Self::Error>;
154);