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);