Skip to main content

rustauth_core/db/
oauth_provider.rs

1//! Shared OAuth 2.1 provider database schema used by `rustauth-oauth-provider` and MCP.
2
3use indexmap::IndexMap;
4
5use super::{DbField, DbFieldType, DbTable, ForeignKey, OnDelete};
6use crate::plugin::PluginSchemaContribution;
7
8pub const OAUTH_CLIENT_MODEL: &str = "oauth_client";
9pub const OAUTH_REFRESH_TOKEN_MODEL: &str = "oauth_refresh_token";
10pub const OAUTH_ACCESS_TOKEN_MODEL: &str = "oauth_access_token";
11pub const OAUTH_CONSENT_MODEL: &str = "oauth_consent";
12
13/// Database schema contributions for the OAuth provider plugin.
14pub fn oauth_provider_schema() -> Vec<PluginSchemaContribution> {
15    vec![
16        PluginSchemaContribution::table(
17            OAUTH_CLIENT_MODEL,
18            table(
19                "oauth_clients",
20                Some(20),
21                [
22                    ("id", field("id", DbFieldType::String)),
23                    (
24                        "client_id",
25                        field("client_id", DbFieldType::String).unique(),
26                    ),
27                    (
28                        "client_secret",
29                        field("client_secret", DbFieldType::String)
30                            .optional()
31                            .hidden(),
32                    ),
33                    (
34                        "client_secret_expires_at",
35                        field("client_secret_expires_at", DbFieldType::Timestamp)
36                            .optional()
37                            .hidden(),
38                    ),
39                    (
40                        "disabled",
41                        field("disabled", DbFieldType::Boolean).optional(),
42                    ),
43                    (
44                        "skip_consent",
45                        field("skip_consent", DbFieldType::Boolean).optional(),
46                    ),
47                    (
48                        "enable_end_session",
49                        field("enable_end_session", DbFieldType::Boolean).optional(),
50                    ),
51                    (
52                        "subject_type",
53                        field("subject_type", DbFieldType::String).optional(),
54                    ),
55                    (
56                        "scopes",
57                        field("scopes", DbFieldType::StringArray).optional(),
58                    ),
59                    (
60                        "user_id",
61                        field("user_id", DbFieldType::String)
62                            .optional()
63                            .indexed()
64                            .references(ForeignKey::new("users", "id", OnDelete::SetNull)),
65                    ),
66                    (
67                        "created_at",
68                        field("created_at", DbFieldType::Timestamp).generated(),
69                    ),
70                    (
71                        "updated_at",
72                        field("updated_at", DbFieldType::Timestamp).generated(),
73                    ),
74                    ("name", field("name", DbFieldType::String).optional()),
75                    ("uri", field("uri", DbFieldType::String).optional()),
76                    ("icon", field("icon", DbFieldType::String).optional()),
77                    (
78                        "contacts",
79                        field("contacts", DbFieldType::StringArray).optional(),
80                    ),
81                    ("tos", field("tos", DbFieldType::String).optional()),
82                    ("policy", field("policy", DbFieldType::String).optional()),
83                    (
84                        "software_id",
85                        field("software_id", DbFieldType::String).optional(),
86                    ),
87                    (
88                        "software_version",
89                        field("software_version", DbFieldType::String).optional(),
90                    ),
91                    (
92                        "software_statement",
93                        field("software_statement", DbFieldType::String).optional(),
94                    ),
95                    (
96                        "redirect_uris",
97                        field("redirect_uris", DbFieldType::StringArray),
98                    ),
99                    (
100                        "post_logout_redirect_uris",
101                        field("post_logout_redirect_uris", DbFieldType::StringArray).optional(),
102                    ),
103                    (
104                        "token_endpoint_auth_method",
105                        field("token_endpoint_auth_method", DbFieldType::String).optional(),
106                    ),
107                    (
108                        "grant_types",
109                        field("grant_types", DbFieldType::StringArray).optional(),
110                    ),
111                    (
112                        "response_types",
113                        field("response_types", DbFieldType::StringArray).optional(),
114                    ),
115                    ("public", field("public", DbFieldType::Boolean).optional()),
116                    ("type", field("type", DbFieldType::String).optional()),
117                    (
118                        "require_pkce",
119                        field("require_pkce", DbFieldType::Boolean).optional(),
120                    ),
121                    (
122                        "reference_id",
123                        field("reference_id", DbFieldType::String)
124                            .optional()
125                            .indexed(),
126                    ),
127                    ("metadata", field("metadata", DbFieldType::Json).optional()),
128                ],
129            ),
130        ),
131        PluginSchemaContribution::table(
132            OAUTH_REFRESH_TOKEN_MODEL,
133            table(
134                "oauth_refresh_tokens",
135                Some(21),
136                [
137                    ("id", field("id", DbFieldType::String)),
138                    (
139                        "token",
140                        field("token", DbFieldType::String).indexed().hidden(),
141                    ),
142                    (
143                        "client_id",
144                        field("client_id", DbFieldType::String)
145                            .indexed()
146                            .references(ForeignKey::new(
147                                "oauth_clients",
148                                "client_id",
149                                OnDelete::Cascade,
150                            )),
151                    ),
152                    (
153                        "session_id",
154                        field("session_id", DbFieldType::String)
155                            .optional()
156                            .references(ForeignKey::new("sessions", "id", OnDelete::SetNull)),
157                    ),
158                    (
159                        "user_id",
160                        field("user_id", DbFieldType::String)
161                            .indexed()
162                            .references(ForeignKey::new("users", "id", OnDelete::Cascade)),
163                    ),
164                    (
165                        "reference_id",
166                        field("reference_id", DbFieldType::String).optional(),
167                    ),
168                    ("expires_at", field("expires_at", DbFieldType::Timestamp)),
169                    (
170                        "created_at",
171                        field("created_at", DbFieldType::Timestamp).generated(),
172                    ),
173                    (
174                        "revoked",
175                        field("revoked", DbFieldType::Timestamp).optional(),
176                    ),
177                    (
178                        "auth_time",
179                        field("auth_time", DbFieldType::Timestamp).optional(),
180                    ),
181                    ("scopes", field("scopes", DbFieldType::StringArray)),
182                ],
183            ),
184        ),
185        PluginSchemaContribution::table(
186            OAUTH_ACCESS_TOKEN_MODEL,
187            table(
188                "oauth_access_tokens",
189                Some(22),
190                [
191                    ("id", field("id", DbFieldType::String)),
192                    (
193                        "token",
194                        field("token", DbFieldType::String).unique().hidden(),
195                    ),
196                    (
197                        "client_id",
198                        field("client_id", DbFieldType::String)
199                            .indexed()
200                            .references(ForeignKey::new(
201                                "oauth_clients",
202                                "client_id",
203                                OnDelete::Cascade,
204                            )),
205                    ),
206                    (
207                        "session_id",
208                        field("session_id", DbFieldType::String)
209                            .optional()
210                            .references(ForeignKey::new("sessions", "id", OnDelete::SetNull)),
211                    ),
212                    (
213                        "user_id",
214                        field("user_id", DbFieldType::String)
215                            .optional()
216                            .indexed()
217                            .references(ForeignKey::new("users", "id", OnDelete::SetNull)),
218                    ),
219                    (
220                        "reference_id",
221                        field("reference_id", DbFieldType::String).optional(),
222                    ),
223                    (
224                        "refresh_id",
225                        field("refresh_id", DbFieldType::String)
226                            .optional()
227                            .references(ForeignKey::new(
228                                "oauth_refresh_tokens",
229                                "id",
230                                OnDelete::Cascade,
231                            )),
232                    ),
233                    ("expires_at", field("expires_at", DbFieldType::Timestamp)),
234                    (
235                        "created_at",
236                        field("created_at", DbFieldType::Timestamp).generated(),
237                    ),
238                    ("scopes", field("scopes", DbFieldType::StringArray)),
239                ],
240            ),
241        ),
242        PluginSchemaContribution::table(
243            OAUTH_CONSENT_MODEL,
244            table(
245                "oauth_consents",
246                Some(23),
247                [
248                    ("id", field("id", DbFieldType::String)),
249                    (
250                        "client_id",
251                        field("client_id", DbFieldType::String)
252                            .indexed()
253                            .references(ForeignKey::new(
254                                "oauth_clients",
255                                "client_id",
256                                OnDelete::Cascade,
257                            )),
258                    ),
259                    (
260                        "user_id",
261                        field("user_id", DbFieldType::String)
262                            .optional()
263                            .indexed()
264                            .references(ForeignKey::new("users", "id", OnDelete::Cascade)),
265                    ),
266                    (
267                        "reference_id",
268                        field("reference_id", DbFieldType::String).optional(),
269                    ),
270                    ("scopes", field("scopes", DbFieldType::StringArray)),
271                    (
272                        "created_at",
273                        field("created_at", DbFieldType::Timestamp).generated(),
274                    ),
275                    (
276                        "updated_at",
277                        field("updated_at", DbFieldType::Timestamp).generated(),
278                    ),
279                ],
280            ),
281        ),
282    ]
283}
284
285fn table<const N: usize>(name: &str, order: Option<u16>, fields: [(&str, DbField); N]) -> DbTable {
286    DbTable {
287        name: name.to_owned(),
288        fields: fields
289            .into_iter()
290            .map(|(logical_name, field)| (logical_name.to_owned(), field))
291            .collect::<IndexMap<_, _>>(),
292        order,
293    }
294}
295
296fn field(name: &str, field_type: DbFieldType) -> DbField {
297    DbField::new(name, field_type)
298}