mas_storage/oauth2/refresh_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 mas_data_model::{AccessToken, RefreshToken, Session};
9use rand_core::RngCore;
10use ulid::Ulid;
11
12use crate::{Clock, repository_impl};
13
14/// An [`OAuth2RefreshTokenRepository`] helps interacting with [`RefreshToken`]
15/// saved in the storage backend
16#[async_trait]
17pub trait OAuth2RefreshTokenRepository: Send + Sync {
18 /// The error type returned by the repository
19 type Error;
20
21 /// Lookup a refresh token by its ID
22 ///
23 /// Returns `None` if no [`RefreshToken`] was found
24 ///
25 /// # Parameters
26 ///
27 /// * `id`: The ID of the [`RefreshToken`] to lookup
28 ///
29 /// # Errors
30 ///
31 /// Returns [`Self::Error`] if the underlying repository fails
32 async fn lookup(&mut self, id: Ulid) -> Result<Option<RefreshToken>, Self::Error>;
33
34 /// Find a refresh token by its token
35 ///
36 /// Returns `None` if no [`RefreshToken`] was found
37 ///
38 /// # Parameters
39 ///
40 /// * `token`: The token of the [`RefreshToken`] to lookup
41 ///
42 /// # Errors
43 ///
44 /// Returns [`Self::Error`] if the underlying repository fails
45 async fn find_by_token(
46 &mut self,
47 refresh_token: &str,
48 ) -> Result<Option<RefreshToken>, Self::Error>;
49
50 /// Add a new refresh token to the database
51 ///
52 /// Returns the newly created [`RefreshToken`]
53 ///
54 /// # Parameters
55 ///
56 /// * `rng`: The random number generator to use
57 /// * `clock`: The clock used to generate timestamps
58 /// * `session`: The [`Session`] in which to create the [`RefreshToken`]
59 /// * `access_token`: The [`AccessToken`] created alongside this
60 /// [`RefreshToken`]
61 /// * `refresh_token`: The refresh token to store
62 ///
63 /// # Errors
64 ///
65 /// Returns [`Self::Error`] if the underlying repository fails
66 async fn add(
67 &mut self,
68 rng: &mut (dyn RngCore + Send),
69 clock: &dyn Clock,
70 session: &Session,
71 access_token: &AccessToken,
72 refresh_token: String,
73 ) -> Result<RefreshToken, Self::Error>;
74
75 /// Consume a refresh token
76 ///
77 /// Returns the updated [`RefreshToken`]
78 ///
79 /// # Parameters
80 ///
81 /// * `clock`: The clock used to generate timestamps
82 /// * `refresh_token`: The [`RefreshToken`] to consume
83 /// * `replaced_by`: The [`RefreshToken`] which replaced this one
84 ///
85 /// # Errors
86 ///
87 /// Returns [`Self::Error`] if the underlying repository fails, or if the
88 /// token was already consumed or revoked
89 async fn consume(
90 &mut self,
91 clock: &dyn Clock,
92 refresh_token: RefreshToken,
93 replaced_by: &RefreshToken,
94 ) -> Result<RefreshToken, Self::Error>;
95
96 /// Revoke a refresh token
97 ///
98 /// Returns the updated [`RefreshToken`]
99 ///
100 /// # Parameters
101 ///
102 /// * `clock`: The clock used to generate timestamps
103 /// * `refresh_token`: The [`RefreshToken`] to revoke
104 ///
105 /// # Errors
106 ///
107 /// Returns [`Self::Error`] if the underlying repository fails, or if the
108 /// token was already revoked or consumed
109 async fn revoke(
110 &mut self,
111 clock: &dyn Clock,
112 refresh_token: RefreshToken,
113 ) -> Result<RefreshToken, Self::Error>;
114}
115
116repository_impl!(OAuth2RefreshTokenRepository:
117 async fn lookup(&mut self, id: Ulid) -> Result<Option<RefreshToken>, Self::Error>;
118
119 async fn find_by_token(
120 &mut self,
121 refresh_token: &str,
122 ) -> Result<Option<RefreshToken>, Self::Error>;
123
124 async fn add(
125 &mut self,
126 rng: &mut (dyn RngCore + Send),
127 clock: &dyn Clock,
128 session: &Session,
129 access_token: &AccessToken,
130 refresh_token: String,
131 ) -> Result<RefreshToken, Self::Error>;
132
133 async fn consume(
134 &mut self,
135 clock: &dyn Clock,
136 refresh_token: RefreshToken,
137 replaced_by: &RefreshToken,
138 ) -> Result<RefreshToken, Self::Error>;
139
140 async fn revoke(
141 &mut self,
142 clock: &dyn Clock,
143 refresh_token: RefreshToken,
144 ) -> Result<RefreshToken, Self::Error>;
145);