mas_storage/oauth2/authorization_grant.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::{AuthorizationCode, AuthorizationGrant, Client, Session};
9use oauth2_types::{requests::ResponseMode, scope::Scope};
10use rand_core::RngCore;
11use ulid::Ulid;
12use url::Url;
13
14use crate::{Clock, repository_impl};
15
16/// An [`OAuth2AuthorizationGrantRepository`] helps interacting with
17/// [`AuthorizationGrant`] saved in the storage backend
18#[async_trait]
19pub trait OAuth2AuthorizationGrantRepository: Send + Sync {
20 /// The error type returned by the repository
21 type Error;
22
23 /// Create a new authorization grant
24 ///
25 /// Returns the newly created authorization grant
26 ///
27 /// # Parameters
28 ///
29 /// * `rng`: A random number generator
30 /// * `clock`: The clock used to generate timestamps
31 /// * `client`: The client that requested the authorization grant
32 /// * `redirect_uri`: The redirect URI the client requested
33 /// * `scope`: The scope the client requested
34 /// * `code`: The authorization code used by this grant, if the `code`
35 /// `response_type` was requested
36 /// * `state`: The state the client sent, if set
37 /// * `nonce`: The nonce the client sent, if set
38 /// * `response_mode`: The response mode the client requested
39 /// * `response_type_id_token`: Whether the `id_token` `response_type` was
40 /// requested
41 /// * `login_hint`: The login_hint the client sent, if set
42 ///
43 /// # Errors
44 ///
45 /// Returns [`Self::Error`] if the underlying repository fails
46 #[allow(clippy::too_many_arguments)]
47 async fn add(
48 &mut self,
49 rng: &mut (dyn RngCore + Send),
50 clock: &dyn Clock,
51 client: &Client,
52 redirect_uri: Url,
53 scope: Scope,
54 code: Option<AuthorizationCode>,
55 state: Option<String>,
56 nonce: Option<String>,
57 response_mode: ResponseMode,
58 response_type_id_token: bool,
59 login_hint: Option<String>,
60 ) -> Result<AuthorizationGrant, Self::Error>;
61
62 /// Lookup an authorization grant by its ID
63 ///
64 /// Returns the authorization grant if found, `None` otherwise
65 ///
66 /// # Parameters
67 ///
68 /// * `id`: The ID of the authorization grant to lookup
69 ///
70 /// # Errors
71 ///
72 /// Returns [`Self::Error`] if the underlying repository fails
73 async fn lookup(&mut self, id: Ulid) -> Result<Option<AuthorizationGrant>, Self::Error>;
74
75 /// Find an authorization grant by its code
76 ///
77 /// Returns the authorization grant if found, `None` otherwise
78 ///
79 /// # Parameters
80 ///
81 /// * `code`: The code of the authorization grant to lookup
82 ///
83 /// # Errors
84 ///
85 /// Returns [`Self::Error`] if the underlying repository fails
86 async fn find_by_code(&mut self, code: &str)
87 -> Result<Option<AuthorizationGrant>, Self::Error>;
88
89 /// Fulfill an authorization grant, by giving the [`Session`] that it
90 /// created
91 ///
92 /// Returns the updated authorization grant
93 ///
94 /// # Parameters
95 ///
96 /// * `clock`: The clock used to generate timestamps
97 /// * `session`: The session that was created using this authorization grant
98 /// * `authorization_grant`: The authorization grant to fulfill
99 ///
100 /// # Errors
101 ///
102 /// Returns [`Self::Error`] if the underlying repository fails
103 async fn fulfill(
104 &mut self,
105 clock: &dyn Clock,
106 session: &Session,
107 authorization_grant: AuthorizationGrant,
108 ) -> Result<AuthorizationGrant, Self::Error>;
109
110 /// Mark an authorization grant as exchanged
111 ///
112 /// Returns the updated authorization grant
113 ///
114 /// # Parameters
115 ///
116 /// * `clock`: The clock used to generate timestamps
117 /// * `authorization_grant`: The authorization grant to mark as exchanged
118 ///
119 /// # Errors
120 ///
121 /// Returns [`Self::Error`] if the underlying repository fails
122 async fn exchange(
123 &mut self,
124 clock: &dyn Clock,
125 authorization_grant: AuthorizationGrant,
126 ) -> Result<AuthorizationGrant, Self::Error>;
127}
128
129repository_impl!(OAuth2AuthorizationGrantRepository:
130 async fn add(
131 &mut self,
132 rng: &mut (dyn RngCore + Send),
133 clock: &dyn Clock,
134 client: &Client,
135 redirect_uri: Url,
136 scope: Scope,
137 code: Option<AuthorizationCode>,
138 state: Option<String>,
139 nonce: Option<String>,
140 response_mode: ResponseMode,
141 response_type_id_token: bool,
142 login_hint: Option<String>,
143 ) -> Result<AuthorizationGrant, Self::Error>;
144
145 async fn lookup(&mut self, id: Ulid) -> Result<Option<AuthorizationGrant>, Self::Error>;
146
147 async fn find_by_code(&mut self, code: &str)
148 -> Result<Option<AuthorizationGrant>, Self::Error>;
149
150 async fn fulfill(
151 &mut self,
152 clock: &dyn Clock,
153 session: &Session,
154 authorization_grant: AuthorizationGrant,
155 ) -> Result<AuthorizationGrant, Self::Error>;
156
157 async fn exchange(
158 &mut self,
159 clock: &dyn Clock,
160 authorization_grant: AuthorizationGrant,
161 ) -> Result<AuthorizationGrant, Self::Error>;
162);