better_auth 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +24 -0
- data/lib/better_auth/adapters/internal_adapter.rb +10 -7
- data/lib/better_auth/adapters/memory.rb +57 -11
- data/lib/better_auth/adapters/sql.rb +123 -20
- data/lib/better_auth/api.rb +114 -9
- data/lib/better_auth/async.rb +70 -0
- data/lib/better_auth/configuration.rb +97 -7
- data/lib/better_auth/context.rb +165 -12
- data/lib/better_auth/cookies.rb +6 -4
- data/lib/better_auth/core.rb +2 -0
- data/lib/better_auth/crypto/jwe.rb +27 -5
- data/lib/better_auth/crypto.rb +32 -0
- data/lib/better_auth/database_hooks.rb +8 -8
- data/lib/better_auth/deprecate.rb +28 -0
- data/lib/better_auth/endpoint.rb +92 -5
- data/lib/better_auth/error.rb +8 -1
- data/lib/better_auth/host.rb +166 -0
- data/lib/better_auth/instrumentation.rb +74 -0
- data/lib/better_auth/logger.rb +31 -0
- data/lib/better_auth/middleware/origin_check.rb +2 -2
- data/lib/better_auth/oauth2.rb +94 -0
- data/lib/better_auth/plugins/admin/schema.rb +2 -2
- data/lib/better_auth/plugins/admin.rb +344 -16
- data/lib/better_auth/plugins/anonymous.rb +37 -3
- data/lib/better_auth/plugins/device_authorization.rb +102 -5
- data/lib/better_auth/plugins/dub.rb +148 -0
- data/lib/better_auth/plugins/email_otp.rb +261 -19
- data/lib/better_auth/plugins/expo.rb +17 -1
- data/lib/better_auth/plugins/generic_oauth.rb +67 -35
- data/lib/better_auth/plugins/jwt.rb +37 -4
- data/lib/better_auth/plugins/last_login_method.rb +2 -2
- data/lib/better_auth/plugins/magic_link.rb +66 -3
- data/lib/better_auth/plugins/mcp/authorization.rb +111 -0
- data/lib/better_auth/plugins/mcp/config.rb +51 -0
- data/lib/better_auth/plugins/mcp/consent.rb +31 -0
- data/lib/better_auth/plugins/mcp/legacy_aliases.rb +39 -0
- data/lib/better_auth/plugins/mcp/metadata.rb +81 -0
- data/lib/better_auth/plugins/mcp/registration.rb +31 -0
- data/lib/better_auth/plugins/mcp/resource_handler.rb +37 -0
- data/lib/better_auth/plugins/mcp/schema.rb +91 -0
- data/lib/better_auth/plugins/mcp/token.rb +108 -0
- data/lib/better_auth/plugins/mcp/userinfo.rb +37 -0
- data/lib/better_auth/plugins/mcp.rb +111 -263
- data/lib/better_auth/plugins/multi_session.rb +61 -3
- data/lib/better_auth/plugins/oauth_protocol.rb +173 -30
- data/lib/better_auth/plugins/oauth_proxy.rb +26 -6
- data/lib/better_auth/plugins/oidc_provider.rb +118 -14
- data/lib/better_auth/plugins/one_tap.rb +7 -2
- data/lib/better_auth/plugins/one_time_token.rb +42 -2
- data/lib/better_auth/plugins/open_api.rb +163 -318
- data/lib/better_auth/plugins/organization/schema.rb +6 -0
- data/lib/better_auth/plugins/organization.rb +186 -56
- data/lib/better_auth/plugins/phone_number.rb +141 -6
- data/lib/better_auth/plugins/siwe.rb +69 -3
- data/lib/better_auth/plugins/two_factor.rb +118 -41
- data/lib/better_auth/plugins/username.rb +57 -2
- data/lib/better_auth/rate_limiter.rb +38 -0
- data/lib/better_auth/request_state.rb +44 -0
- data/lib/better_auth/response.rb +42 -0
- data/lib/better_auth/router.rb +7 -1
- data/lib/better_auth/routes/account.rb +220 -42
- data/lib/better_auth/routes/email_verification.rb +98 -14
- data/lib/better_auth/routes/password.rb +126 -8
- data/lib/better_auth/routes/session.rb +128 -13
- data/lib/better_auth/routes/sign_in.rb +26 -2
- data/lib/better_auth/routes/sign_out.rb +13 -1
- data/lib/better_auth/routes/sign_up.rb +70 -4
- data/lib/better_auth/routes/social.rb +132 -7
- data/lib/better_auth/routes/user.rb +228 -20
- data/lib/better_auth/routes/validation.rb +50 -0
- data/lib/better_auth/secret_config.rb +115 -0
- data/lib/better_auth/session.rb +13 -2
- data/lib/better_auth/url_helpers.rb +206 -0
- data/lib/better_auth/version.rb +1 -1
- data/lib/better_auth.rb +12 -0
- metadata +23 -1
|
@@ -1,6 +1,165 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module BetterAuth
|
|
4
|
+
module OpenAPI
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def object_schema(properties, required: [])
|
|
8
|
+
{
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: properties,
|
|
11
|
+
required: required
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def json_request_body(schema, required: true)
|
|
16
|
+
request = {
|
|
17
|
+
content: {
|
|
18
|
+
"application/json" => {
|
|
19
|
+
schema: schema
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
request[:required] = true if required
|
|
24
|
+
request
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def json_response(description, schema)
|
|
28
|
+
{
|
|
29
|
+
description: description,
|
|
30
|
+
content: {
|
|
31
|
+
"application/json" => {
|
|
32
|
+
schema: schema
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def session_response_schema(description:, nullable_url: false)
|
|
39
|
+
object_schema(
|
|
40
|
+
{
|
|
41
|
+
redirect: {type: "boolean", enum: [false]},
|
|
42
|
+
token: {type: "string", description: "Session token"},
|
|
43
|
+
url: nullable_url ? {type: "string", nullable: true} : {type: "string"},
|
|
44
|
+
user: {type: "object", "$ref": "#/components/schemas/User"}
|
|
45
|
+
},
|
|
46
|
+
required: ["redirect", "token", "user"]
|
|
47
|
+
).merge(description: description)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def user_response_schema
|
|
51
|
+
object_schema(
|
|
52
|
+
{
|
|
53
|
+
id: {type: "string", description: "The unique identifier of the user"},
|
|
54
|
+
email: {type: "string", format: "email", description: "The email address of the user"},
|
|
55
|
+
name: {type: "string", description: "The name of the user"},
|
|
56
|
+
image: {type: "string", format: "uri", nullable: true, description: "The profile image URL of the user"},
|
|
57
|
+
emailVerified: {type: "boolean", description: "Whether the email has been verified"},
|
|
58
|
+
createdAt: {type: "string", format: "date-time", description: "When the user was created"},
|
|
59
|
+
updatedAt: {type: "string", format: "date-time", description: "When the user was last updated"}
|
|
60
|
+
},
|
|
61
|
+
required: ["id", "email", "name", "emailVerified", "createdAt", "updatedAt"]
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def session_response_schema_pair
|
|
66
|
+
object_schema(
|
|
67
|
+
{
|
|
68
|
+
session: {type: "object", "$ref": "#/components/schemas/Session"},
|
|
69
|
+
user: {type: "object", "$ref": "#/components/schemas/User"}
|
|
70
|
+
},
|
|
71
|
+
required: ["session", "user"]
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def status_response_schema(extra_properties = {}, required: ["status"])
|
|
76
|
+
object_schema(
|
|
77
|
+
{
|
|
78
|
+
status: {type: "boolean"}
|
|
79
|
+
}.merge(extra_properties),
|
|
80
|
+
required: required
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def success_response_schema
|
|
85
|
+
object_schema(
|
|
86
|
+
{
|
|
87
|
+
success: {type: "boolean"}
|
|
88
|
+
},
|
|
89
|
+
required: ["success"]
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def empty_request_body
|
|
94
|
+
{
|
|
95
|
+
content: {
|
|
96
|
+
"application/json" => {
|
|
97
|
+
schema: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: {}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def responses(responses = nil)
|
|
107
|
+
{"200" => success_response}.merge(default_error_responses).merge(responses || {})
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def success_response
|
|
111
|
+
json_response(
|
|
112
|
+
"Success",
|
|
113
|
+
{
|
|
114
|
+
type: "object",
|
|
115
|
+
properties: {}
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def default_error_responses
|
|
121
|
+
{
|
|
122
|
+
"400" => error_response("Bad Request. Usually due to missing parameters, or invalid parameters.", required: true),
|
|
123
|
+
"401" => error_response("Unauthorized. Due to missing or invalid authentication.", required: true),
|
|
124
|
+
"403" => error_response("Forbidden. You do not have permission to access this resource or to perform this action."),
|
|
125
|
+
"404" => error_response("Not Found. The requested resource was not found."),
|
|
126
|
+
"429" => error_response("Too Many Requests. You have exceeded the rate limit. Try again later."),
|
|
127
|
+
"500" => error_response("Internal Server Error. This is a problem with the server that you cannot fix.")
|
|
128
|
+
}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def error_response(description, required: false)
|
|
132
|
+
schema = {
|
|
133
|
+
type: "object",
|
|
134
|
+
properties: {
|
|
135
|
+
message: {
|
|
136
|
+
type: "string"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
schema[:required] = ["message"] if required
|
|
141
|
+
json_response(description, schema)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def default_metadata(path, methods)
|
|
145
|
+
method = Array(methods).reject { |value| value.to_s == "*" }.first.to_s.upcase
|
|
146
|
+
{
|
|
147
|
+
operationId: operation_id(path, method),
|
|
148
|
+
description: "#{method} #{path}"
|
|
149
|
+
}
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def operation_id(path, method)
|
|
153
|
+
parts = path.to_s.split("/").reject(&:empty?).map do |part|
|
|
154
|
+
part.delete_prefix(":").gsub(/[^a-zA-Z0-9]+/, " ").split.map(&:capitalize).join
|
|
155
|
+
end
|
|
156
|
+
base = parts.join
|
|
157
|
+
return method.downcase if base.empty?
|
|
158
|
+
|
|
159
|
+
"#{method.to_s.downcase}#{base}"
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
4
163
|
module Plugins
|
|
5
164
|
module_function
|
|
6
165
|
|
|
@@ -105,338 +264,24 @@ module BetterAuth
|
|
|
105
264
|
metadata = endpoint.metadata[:openapi] || {}
|
|
106
265
|
operation = {
|
|
107
266
|
tags: Array(metadata[:tags] || [tag]),
|
|
108
|
-
description: metadata[:description]
|
|
109
|
-
operationId: metadata
|
|
267
|
+
description: metadata[:description],
|
|
268
|
+
operationId: metadata[:operationId],
|
|
110
269
|
security: [
|
|
111
270
|
{
|
|
112
271
|
bearerAuth: []
|
|
113
272
|
}
|
|
114
273
|
],
|
|
115
274
|
parameters: metadata[:parameters] || [],
|
|
116
|
-
responses:
|
|
275
|
+
responses: OpenAPI.responses(metadata[:responses])
|
|
117
276
|
}
|
|
118
277
|
|
|
119
278
|
if %w[POST PATCH PUT].include?(method)
|
|
120
|
-
operation[:requestBody] = metadata[:requestBody] ||
|
|
279
|
+
operation[:requestBody] = metadata[:requestBody] || OpenAPI.empty_request_body
|
|
121
280
|
end
|
|
122
281
|
|
|
123
282
|
operation
|
|
124
283
|
end
|
|
125
284
|
|
|
126
|
-
def route_description(path, method)
|
|
127
|
-
route_open_api_metadata(path, method)[:description]
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def route_operation_id(path, method)
|
|
131
|
-
route_open_api_metadata(path, method)[:operationId]
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def route_request_body(path, method)
|
|
135
|
-
route_open_api_metadata(path, method)[:requestBody]
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def route_responses(path, method)
|
|
139
|
-
route_open_api_metadata(path, method)[:responses]
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def route_open_api_metadata(path, method)
|
|
143
|
-
case [path, method.to_s.upcase]
|
|
144
|
-
when ["/change-email", "POST"]
|
|
145
|
-
{
|
|
146
|
-
operationId: "changeEmail",
|
|
147
|
-
requestBody: {
|
|
148
|
-
required: true,
|
|
149
|
-
content: {
|
|
150
|
-
"application/json" => {
|
|
151
|
-
schema: object_schema(
|
|
152
|
-
{
|
|
153
|
-
callbackURL: {type: ["string", "null"], description: "The URL to redirect to after email verification"},
|
|
154
|
-
newEmail: {type: "string", description: "The new email address to set must be a valid email address"}
|
|
155
|
-
},
|
|
156
|
-
required: ["newEmail"]
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
responses: {
|
|
162
|
-
"200" => {
|
|
163
|
-
description: "Email change request processed successfully",
|
|
164
|
-
content: {
|
|
165
|
-
"application/json" => {
|
|
166
|
-
schema: object_schema(
|
|
167
|
-
{
|
|
168
|
-
message: {
|
|
169
|
-
type: "string",
|
|
170
|
-
nullable: true,
|
|
171
|
-
enum: ["Email updated", "Verification email sent"],
|
|
172
|
-
description: "Status message of the email change process"
|
|
173
|
-
},
|
|
174
|
-
status: {type: "boolean", description: "Indicates if the request was successful"},
|
|
175
|
-
user: {type: "object", "$ref": "#/components/schemas/User"}
|
|
176
|
-
},
|
|
177
|
-
required: ["status"]
|
|
178
|
-
)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
"422" => error_response("Unprocessable Entity. Email already exists")
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
when ["/change-password", "POST"]
|
|
186
|
-
{
|
|
187
|
-
description: "Change the password of the user",
|
|
188
|
-
operationId: "changePassword",
|
|
189
|
-
requestBody: {
|
|
190
|
-
required: true,
|
|
191
|
-
content: {
|
|
192
|
-
"application/json" => {
|
|
193
|
-
schema: object_schema(
|
|
194
|
-
{
|
|
195
|
-
newPassword: {type: "string", description: "The new password to set"},
|
|
196
|
-
currentPassword: {type: "string", description: "The current password is required"},
|
|
197
|
-
revokeOtherSessions: {type: ["boolean", "null"], description: "Must be a boolean value"}
|
|
198
|
-
},
|
|
199
|
-
required: ["newPassword", "currentPassword"]
|
|
200
|
-
)
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
responses: {
|
|
205
|
-
"200" => {
|
|
206
|
-
description: "Password successfully changed",
|
|
207
|
-
content: {
|
|
208
|
-
"application/json" => {
|
|
209
|
-
schema: object_schema(
|
|
210
|
-
{
|
|
211
|
-
token: {type: "string", nullable: true, description: "New session token if other sessions were revoked"},
|
|
212
|
-
user: open_api_user_response_schema
|
|
213
|
-
},
|
|
214
|
-
required: ["user"]
|
|
215
|
-
)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
when ["/sign-in/email", "POST"]
|
|
222
|
-
{
|
|
223
|
-
description: "Sign in with email and password",
|
|
224
|
-
operationId: "signInEmail",
|
|
225
|
-
requestBody: {
|
|
226
|
-
required: true,
|
|
227
|
-
content: {
|
|
228
|
-
"application/json" => {
|
|
229
|
-
schema: object_schema(
|
|
230
|
-
{
|
|
231
|
-
email: {type: "string", description: "Email of the user"},
|
|
232
|
-
password: {type: "string", description: "Password of the user"},
|
|
233
|
-
callbackURL: {type: ["string", "null"], description: "Callback URL to use as a redirect for email verification"},
|
|
234
|
-
rememberMe: {type: ["boolean", "null"], default: true, description: "If this is false, the session will not be remembered. Default is `true`."}
|
|
235
|
-
},
|
|
236
|
-
required: ["email", "password"]
|
|
237
|
-
)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
responses: {
|
|
242
|
-
"200" => {
|
|
243
|
-
description: "Success - Returns either session details or redirect URL",
|
|
244
|
-
content: {
|
|
245
|
-
"application/json" => {
|
|
246
|
-
schema: session_response_schema(description: "Session response when idToken is provided", nullable_url: true)
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
when ["/sign-in/social", "POST"]
|
|
253
|
-
{
|
|
254
|
-
description: "Sign in with a social provider",
|
|
255
|
-
operationId: "socialSignIn",
|
|
256
|
-
requestBody: {
|
|
257
|
-
required: true,
|
|
258
|
-
content: {
|
|
259
|
-
"application/json" => {
|
|
260
|
-
schema: object_schema(
|
|
261
|
-
{
|
|
262
|
-
provider: {type: "string"},
|
|
263
|
-
callbackURL: {type: ["string", "null"], description: "Callback URL to redirect to after the user has signed in"},
|
|
264
|
-
errorCallbackURL: {type: ["string", "null"], description: "Callback URL to redirect to if an error happens"},
|
|
265
|
-
newUserCallbackURL: {type: ["string", "null"]},
|
|
266
|
-
disableRedirect: {type: ["boolean", "null"], description: "Disable automatic redirection to the provider. Useful for handling the redirection yourself"},
|
|
267
|
-
requestSignUp: {type: ["boolean", "null"], description: "Explicitly request sign-up. Useful when disableImplicitSignUp is true for this provider"},
|
|
268
|
-
loginHint: {type: ["string", "null"], description: "The login hint to use for the authorization code request"},
|
|
269
|
-
additionalData: {type: ["string", "null"]},
|
|
270
|
-
scopes: {type: ["array", "null"], description: "Array of scopes to request from the provider. This will override the default scopes passed."},
|
|
271
|
-
idToken: {
|
|
272
|
-
type: ["object", "null"],
|
|
273
|
-
properties: {
|
|
274
|
-
token: {type: "string", description: "ID token from the provider"},
|
|
275
|
-
accessToken: {type: ["string", "null"], description: "Access token from the provider"},
|
|
276
|
-
refreshToken: {type: ["string", "null"], description: "Refresh token from the provider"},
|
|
277
|
-
expiresAt: {type: ["number", "null"], description: "Expiry date of the token"},
|
|
278
|
-
nonce: {type: ["string", "null"], description: "Nonce used to generate the token"}
|
|
279
|
-
},
|
|
280
|
-
required: ["token"]
|
|
281
|
-
}
|
|
282
|
-
},
|
|
283
|
-
required: ["provider"]
|
|
284
|
-
)
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
},
|
|
288
|
-
responses: {
|
|
289
|
-
"200" => {
|
|
290
|
-
description: "Success - Returns either session details or redirect URL",
|
|
291
|
-
content: {
|
|
292
|
-
"application/json" => {
|
|
293
|
-
schema: session_response_schema(description: "Session response when idToken is provided")
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
when ["/sign-up/email", "POST"]
|
|
300
|
-
{
|
|
301
|
-
description: "Sign up a user using email and password",
|
|
302
|
-
operationId: "signUpWithEmailAndPassword",
|
|
303
|
-
requestBody: {
|
|
304
|
-
content: {
|
|
305
|
-
"application/json" => {
|
|
306
|
-
schema: object_schema(
|
|
307
|
-
{
|
|
308
|
-
name: {type: "string", description: "The name of the user"},
|
|
309
|
-
email: {type: "string", description: "The email of the user"},
|
|
310
|
-
password: {type: "string", description: "The password of the user"},
|
|
311
|
-
image: {type: "string", description: "The profile image URL of the user"},
|
|
312
|
-
callbackURL: {type: "string", description: "The URL to use for email verification callback"},
|
|
313
|
-
rememberMe: {type: "boolean", description: "If this is false, the session will not be remembered. Default is `true`."}
|
|
314
|
-
},
|
|
315
|
-
required: ["name", "email", "password"]
|
|
316
|
-
)
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
responses: {
|
|
321
|
-
"200" => {
|
|
322
|
-
description: "Successfully created user",
|
|
323
|
-
content: {
|
|
324
|
-
"application/json" => {
|
|
325
|
-
schema: object_schema(
|
|
326
|
-
{
|
|
327
|
-
token: {type: "string", nullable: true, description: "Authentication token for the session"},
|
|
328
|
-
user: {type: "object", "$ref": "#/components/schemas/User"}
|
|
329
|
-
},
|
|
330
|
-
required: ["user"]
|
|
331
|
-
)
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
},
|
|
335
|
-
"422" => error_response("Unprocessable Entity. User already exists or failed to create user.")
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
else
|
|
339
|
-
{}
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
def object_schema(properties, required: [])
|
|
344
|
-
{
|
|
345
|
-
type: "object",
|
|
346
|
-
properties: properties,
|
|
347
|
-
required: required
|
|
348
|
-
}
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
def session_response_schema(description:, nullable_url: false)
|
|
352
|
-
object_schema(
|
|
353
|
-
{
|
|
354
|
-
redirect: {type: "boolean", enum: [false]},
|
|
355
|
-
token: {type: "string", description: "Session token"},
|
|
356
|
-
url: nullable_url ? {type: "string", nullable: true} : {type: "string"},
|
|
357
|
-
user: {type: "object", "$ref": "#/components/schemas/User"}
|
|
358
|
-
},
|
|
359
|
-
required: ["redirect", "token", "user"]
|
|
360
|
-
).merge(description: description)
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
def open_api_user_response_schema
|
|
364
|
-
object_schema(
|
|
365
|
-
{
|
|
366
|
-
id: {type: "string", description: "The unique identifier of the user"},
|
|
367
|
-
email: {type: "string", format: "email", description: "The email address of the user"},
|
|
368
|
-
name: {type: "string", description: "The name of the user"},
|
|
369
|
-
image: {type: "string", format: "uri", nullable: true, description: "The profile image URL of the user"},
|
|
370
|
-
emailVerified: {type: "boolean", description: "Whether the email has been verified"},
|
|
371
|
-
createdAt: {type: "string", format: "date-time", description: "When the user was created"},
|
|
372
|
-
updatedAt: {type: "string", format: "date-time", description: "When the user was last updated"}
|
|
373
|
-
},
|
|
374
|
-
required: ["id", "email", "name", "emailVerified", "createdAt", "updatedAt"]
|
|
375
|
-
)
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
def empty_request_body
|
|
379
|
-
{
|
|
380
|
-
content: {
|
|
381
|
-
"application/json" => {
|
|
382
|
-
schema: {
|
|
383
|
-
type: "object",
|
|
384
|
-
properties: {}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
def open_api_responses(responses = nil)
|
|
392
|
-
{"200" => success_response}.merge(default_error_responses).merge(responses || {})
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
def success_response
|
|
396
|
-
{
|
|
397
|
-
description: "Success",
|
|
398
|
-
content: {
|
|
399
|
-
"application/json" => {
|
|
400
|
-
schema: {
|
|
401
|
-
type: "object",
|
|
402
|
-
properties: {}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def default_error_responses
|
|
410
|
-
{
|
|
411
|
-
"400" => error_response("Bad Request. Usually due to missing parameters, or invalid parameters.", required: true),
|
|
412
|
-
"401" => error_response("Unauthorized. Due to missing or invalid authentication.", required: true),
|
|
413
|
-
"403" => error_response("Forbidden. You do not have permission to access this resource or to perform this action."),
|
|
414
|
-
"404" => error_response("Not Found. The requested resource was not found."),
|
|
415
|
-
"429" => error_response("Too Many Requests. You have exceeded the rate limit. Try again later."),
|
|
416
|
-
"500" => error_response("Internal Server Error. This is a problem with the server that you cannot fix.")
|
|
417
|
-
}
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
def error_response(description, required: false)
|
|
421
|
-
schema = {
|
|
422
|
-
type: "object",
|
|
423
|
-
properties: {
|
|
424
|
-
message: {
|
|
425
|
-
type: "string"
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
schema[:required] = ["message"] if required
|
|
430
|
-
{
|
|
431
|
-
description: description,
|
|
432
|
-
content: {
|
|
433
|
-
"application/json" => {
|
|
434
|
-
schema: schema
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
end
|
|
439
|
-
|
|
440
285
|
def open_api_components(options)
|
|
441
286
|
Schema.auth_tables(options).each_with_object({}) do |(model, table), schemas|
|
|
442
287
|
name = model.to_s.split(/[_-]/).map(&:capitalize).join
|
|
@@ -10,6 +10,7 @@ module BetterAuth
|
|
|
10
10
|
organization: {
|
|
11
11
|
model_name: "organizations",
|
|
12
12
|
fields: {
|
|
13
|
+
id: {type: "string", required: true},
|
|
13
14
|
name: {type: "string", required: true, sortable: true},
|
|
14
15
|
slug: {type: "string", required: true, unique: true, sortable: true, index: true},
|
|
15
16
|
logo: {type: "string", required: false},
|
|
@@ -21,6 +22,7 @@ module BetterAuth
|
|
|
21
22
|
member: {
|
|
22
23
|
model_name: "members",
|
|
23
24
|
fields: {
|
|
25
|
+
id: {type: "string", required: true},
|
|
24
26
|
organizationId: {type: "string", required: true, references: {model: "organization", field: "id"}, index: true},
|
|
25
27
|
userId: {type: "string", required: true, references: {model: "user", field: "id"}, index: true},
|
|
26
28
|
role: {type: "string", required: true, default_value: "member", sortable: true},
|
|
@@ -30,6 +32,7 @@ module BetterAuth
|
|
|
30
32
|
invitation: {
|
|
31
33
|
model_name: "invitations",
|
|
32
34
|
fields: {
|
|
35
|
+
id: {type: "string", required: true},
|
|
33
36
|
organizationId: {type: "string", required: true, references: {model: "organization", field: "id"}, index: true},
|
|
34
37
|
email: {type: "string", required: true, sortable: true, index: true},
|
|
35
38
|
role: {type: "string", required: true, sortable: true},
|
|
@@ -50,6 +53,7 @@ module BetterAuth
|
|
|
50
53
|
schema[:team] = {
|
|
51
54
|
model_name: "teams",
|
|
52
55
|
fields: {
|
|
56
|
+
id: {type: "string", required: true},
|
|
53
57
|
name: {type: "string", required: true},
|
|
54
58
|
organizationId: {type: "string", required: true, references: {model: "organization", field: "id"}, index: true},
|
|
55
59
|
createdAt: {type: "date", required: true, default_value: -> { Time.now }},
|
|
@@ -59,6 +63,7 @@ module BetterAuth
|
|
|
59
63
|
schema[:teamMember] = {
|
|
60
64
|
model_name: "team_members",
|
|
61
65
|
fields: {
|
|
66
|
+
id: {type: "string", required: true},
|
|
62
67
|
teamId: {type: "string", required: true, references: {model: "team", field: "id"}, index: true},
|
|
63
68
|
userId: {type: "string", required: true, references: {model: "user", field: "id"}, index: true},
|
|
64
69
|
createdAt: {type: "date", required: false, default_value: -> { Time.now }}
|
|
@@ -72,6 +77,7 @@ module BetterAuth
|
|
|
72
77
|
schema[:organizationRole] = {
|
|
73
78
|
model_name: "organization_roles",
|
|
74
79
|
fields: {
|
|
80
|
+
id: {type: "string", required: true},
|
|
75
81
|
organizationId: {type: "string", required: true, references: {model: "organization", field: "id"}, index: true},
|
|
76
82
|
role: {type: "string", required: true, index: true},
|
|
77
83
|
permission: {type: "string", required: true},
|