@better-auth-ui/core 1.6.30 → 1.6.32
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.
- package/dist/{create-auth-plugin-DcxR23rZ.js → create-auth-plugin-D4wsYnHD.js} +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +46 -15
- package/dist/lib/auth-mutation-keys.d.ts +5 -4
- package/dist/lib/auth-redirect.d.ts +31 -0
- package/dist/lib/view-paths.d.ts +5 -0
- package/dist/plugins/admin/admin-localization.d.ts +5 -0
- package/dist/plugins/admin/admin-mutation-keys.d.ts +9 -0
- package/dist/plugins/admin/admin-plugin.d.ts +32 -0
- package/dist/plugins/device-authorization/device-authorization-localization.d.ts +33 -0
- package/dist/plugins/device-authorization/device-authorization-mutation-keys.d.ts +16 -0
- package/dist/plugins/device-authorization/device-authorization-plugin.d.ts +59 -0
- package/dist/plugins/oauth-provider/oauth-provider-localization.d.ts +25 -0
- package/dist/plugins/oauth-provider/oauth-provider-mutation-keys.d.ts +12 -0
- package/dist/plugins/oauth-provider/oauth-provider-plugin.d.ts +78 -0
- package/dist/plugins/oauth-provider/oauth-provider-query-keys.d.ts +9 -0
- package/dist/plugins.d.ts +10 -0
- package/dist/plugins.js +193 -63
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/lib/auth-mutation-keys.ts +5 -4
- package/src/lib/auth-redirect.ts +105 -0
- package/src/lib/view-paths.ts +6 -0
- package/src/plugins/admin/admin-localization.ts +6 -0
- package/src/plugins/admin/admin-mutation-keys.ts +9 -0
- package/src/plugins/admin/admin-plugin.ts +52 -0
- package/src/plugins/device-authorization/device-authorization-localization.ts +36 -0
- package/src/plugins/device-authorization/device-authorization-mutation-keys.ts +16 -0
- package/src/plugins/device-authorization/device-authorization-plugin.ts +65 -0
- package/src/plugins/oauth-provider/oauth-provider-localization.ts +27 -0
- package/src/plugins/oauth-provider/oauth-provider-mutation-keys.ts +12 -0
- package/src/plugins/oauth-provider/oauth-provider-plugin.ts +132 -0
- package/src/plugins/oauth-provider/oauth-provider-query-keys.ts +10 -0
- package/src/plugins.ts +10 -0
package/dist/plugins.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
import { n as e, r as t, t as n } from "./create-auth-plugin-
|
|
2
|
-
//#region src/plugins/
|
|
3
|
-
var r = {
|
|
1
|
+
import { n as e, r as t, t as n } from "./create-auth-plugin-D4wsYnHD.js";
|
|
2
|
+
//#region src/plugins/admin/admin-localization.ts
|
|
3
|
+
var r = { stopImpersonating: "Stop impersonating" }, i = {
|
|
4
|
+
all: ["auth", "admin"],
|
|
5
|
+
stopImpersonating: [
|
|
6
|
+
"auth",
|
|
7
|
+
"admin",
|
|
8
|
+
"stopImpersonating"
|
|
9
|
+
]
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/plugins/admin/admin-plugin.ts
|
|
13
|
+
function a(e) {
|
|
14
|
+
return !e || typeof e != "object" || !("session" in e) || !e.session || typeof e.session != "object" || !("impersonatedBy" in e.session) ? !1 : typeof e.session.impersonatedBy == "string" && e.session.impersonatedBy.length > 0;
|
|
15
|
+
}
|
|
16
|
+
var o = n("admin", (e = {}) => ({ localization: {
|
|
17
|
+
...r,
|
|
18
|
+
...e.localization
|
|
19
|
+
} })), s = {
|
|
4
20
|
apiKey: "API key",
|
|
5
21
|
apiKeys: "API keys",
|
|
6
22
|
apiKeysDescription: "Create an API key for programmatic access to your account.",
|
|
@@ -12,7 +28,7 @@ var r = {
|
|
|
12
28
|
deleteApiKey: "Delete API key",
|
|
13
29
|
deleteApiKeyWarning: "This action cannot be undone. Any service using this API key will stop working immediately.",
|
|
14
30
|
dismissNewKey: "I've saved my key"
|
|
15
|
-
},
|
|
31
|
+
}, c = {
|
|
16
32
|
all: ["auth", "apiKey"],
|
|
17
33
|
create: [
|
|
18
34
|
"auth",
|
|
@@ -24,57 +40,101 @@ var r = {
|
|
|
24
40
|
"apiKey",
|
|
25
41
|
"delete"
|
|
26
42
|
]
|
|
27
|
-
},
|
|
43
|
+
}, l = n("apiKey", (e = {}) => ({
|
|
28
44
|
localization: {
|
|
29
|
-
...
|
|
45
|
+
...s,
|
|
30
46
|
...e.localization
|
|
31
47
|
},
|
|
32
48
|
organization: e.organization ?? !1
|
|
33
|
-
})),
|
|
49
|
+
})), u = {
|
|
34
50
|
all: (t) => [...e.user(t), "apiKey"],
|
|
35
|
-
lists: (e) => [...
|
|
36
|
-
list: (e, t) => [...
|
|
37
|
-
},
|
|
51
|
+
lists: (e) => [...u.all(e), "list"],
|
|
52
|
+
list: (e, t) => [...u.lists(e), t ?? null]
|
|
53
|
+
}, d = {
|
|
38
54
|
deleteAccount: "Delete account",
|
|
39
55
|
deleteAccountDescription: "Permanently remove your account and all associated data. This cannot be undone.",
|
|
40
56
|
deleteUserVerificationSent: "Check your email to confirm account deletion.",
|
|
41
57
|
deleteUserSuccess: "Your account has been deleted."
|
|
42
|
-
},
|
|
58
|
+
}, f = { deleteUser: ["auth", "deleteUser"] }, p = n("deleteUser", (e = {}) => ({
|
|
43
59
|
localization: {
|
|
44
|
-
...
|
|
60
|
+
...d,
|
|
45
61
|
...e.localization
|
|
46
62
|
},
|
|
47
63
|
sendDeleteAccountVerification: e.sendDeleteAccountVerification ?? !1
|
|
48
|
-
})),
|
|
64
|
+
})), m = {
|
|
65
|
+
deviceAuthorization: "Device Authorization",
|
|
66
|
+
deviceAuthorizationDescription: "Enter the code displayed on your device.",
|
|
67
|
+
deviceCode: "Device code",
|
|
68
|
+
invalidDeviceCode: "The code is invalid or has expired.",
|
|
69
|
+
continue: "Continue",
|
|
70
|
+
approveDevice: "Approve Device",
|
|
71
|
+
approveDeviceDescription: "A device is requesting access to your account.",
|
|
72
|
+
signedInAs: "Signed in as",
|
|
73
|
+
approve: "Approve",
|
|
74
|
+
deny: "Deny",
|
|
75
|
+
deviceApproved: "Device Approved",
|
|
76
|
+
deviceApprovedDescription: "The device can now access your account. You can return to it and continue.",
|
|
77
|
+
deviceDenied: "Device Denied",
|
|
78
|
+
deviceDeniedDescription: "The device was not granted access to your account.",
|
|
79
|
+
returnToApplication: "Return to application"
|
|
80
|
+
}, h = {
|
|
81
|
+
all: ["auth", "deviceAuthorization"],
|
|
82
|
+
verify: [
|
|
83
|
+
"auth",
|
|
84
|
+
"deviceAuthorization",
|
|
85
|
+
"verify"
|
|
86
|
+
],
|
|
87
|
+
approve: [
|
|
88
|
+
"auth",
|
|
89
|
+
"deviceAuthorization",
|
|
90
|
+
"approve"
|
|
91
|
+
],
|
|
92
|
+
deny: [
|
|
93
|
+
"auth",
|
|
94
|
+
"deviceAuthorization",
|
|
95
|
+
"deny"
|
|
96
|
+
]
|
|
97
|
+
}, g = 8;
|
|
98
|
+
function _(e) {
|
|
99
|
+
return e === void 0 || !Number.isFinite(e) ? g : Math.max(1, Math.floor(e));
|
|
100
|
+
}
|
|
101
|
+
var v = n("deviceAuthorization", (e = {}) => ({
|
|
102
|
+
localization: {
|
|
103
|
+
...m,
|
|
104
|
+
...e.localization
|
|
105
|
+
},
|
|
106
|
+
userCodeLength: _(e.userCodeLength),
|
|
107
|
+
viewPaths: { auth: { deviceAuthorization: e.path ?? "device" } }
|
|
108
|
+
})), y = {
|
|
49
109
|
lastUsed: "Last used",
|
|
50
110
|
lastUsedShort: "Last"
|
|
51
|
-
},
|
|
52
|
-
...
|
|
111
|
+
}, b = n("lastLoginMethod", (e = {}) => ({ localization: {
|
|
112
|
+
...y,
|
|
53
113
|
...e.localization
|
|
54
|
-
} })),
|
|
114
|
+
} })), x = {
|
|
55
115
|
magicLink: "Magic Link",
|
|
56
116
|
sendMagicLink: "Send Magic Link",
|
|
57
117
|
magicLinkSent: "Check your email for the magic link",
|
|
58
118
|
magicLinkSentTo: "We sent a magic link to {{email}}"
|
|
59
|
-
},
|
|
119
|
+
}, S = { signIn: [
|
|
60
120
|
"auth",
|
|
61
121
|
"signIn",
|
|
62
122
|
"magicLink"
|
|
63
|
-
] },
|
|
123
|
+
] }, C = n("magicLink", (e = {}) => ({
|
|
64
124
|
localization: {
|
|
65
|
-
...
|
|
125
|
+
...x,
|
|
66
126
|
...e.localization
|
|
67
127
|
},
|
|
68
128
|
viewPaths: { auth: {
|
|
69
129
|
magicLink: e.path ?? "magic-link",
|
|
70
130
|
magicLinkSent: e.sentPath ?? "magic-link-sent"
|
|
71
131
|
} }
|
|
72
|
-
})),
|
|
132
|
+
})), w = {
|
|
73
133
|
switchAccount: "Switch Account",
|
|
74
134
|
addAccount: "Add Account",
|
|
75
135
|
manageAccounts: "Manage accounts",
|
|
76
136
|
manageAccountsDescription: "Manage your accounts for secure access."
|
|
77
|
-
},
|
|
137
|
+
}, T = {
|
|
78
138
|
all: ["auth", "multiSession"],
|
|
79
139
|
revoke: [
|
|
80
140
|
"auth",
|
|
@@ -86,14 +146,84 @@ var r = {
|
|
|
86
146
|
"multiSession",
|
|
87
147
|
"setActive"
|
|
88
148
|
]
|
|
89
|
-
},
|
|
90
|
-
...
|
|
149
|
+
}, E = n("multiSession", (e = {}) => ({ localization: {
|
|
150
|
+
...w,
|
|
91
151
|
...e.localization
|
|
92
|
-
} })),
|
|
152
|
+
} })), D = {
|
|
93
153
|
all: (t) => [...e.user(t), "multiSession"],
|
|
94
|
-
lists: (e) => [...
|
|
95
|
-
list: (e, t) => [...
|
|
96
|
-
},
|
|
154
|
+
lists: (e) => [...D.all(e), "list"],
|
|
155
|
+
list: (e, t) => [...D.lists(e), t ?? null]
|
|
156
|
+
}, O = {
|
|
157
|
+
authorize: "Authorize {{client}}",
|
|
158
|
+
authorizationDescription: "{{client}} wants to access your account.",
|
|
159
|
+
requestedPermissions: "This will allow {{client}} to:",
|
|
160
|
+
signedInAs: "Signed in as",
|
|
161
|
+
allow: "Allow",
|
|
162
|
+
cancel: "Cancel",
|
|
163
|
+
privacyPolicy: "Privacy policy",
|
|
164
|
+
termsOfService: "Terms of service",
|
|
165
|
+
invalidRequest: "Invalid authorization request",
|
|
166
|
+
invalidRequestDescription: "This authorization request is missing required information or is no longer valid.",
|
|
167
|
+
application: "Application"
|
|
168
|
+
}, k = {
|
|
169
|
+
all: ["auth", "oauthProvider"],
|
|
170
|
+
consent: [
|
|
171
|
+
"auth",
|
|
172
|
+
"oauthProvider",
|
|
173
|
+
"consent"
|
|
174
|
+
]
|
|
175
|
+
}, A = {
|
|
176
|
+
openid: {
|
|
177
|
+
label: "Verify your identity",
|
|
178
|
+
description: "Access your unique account identifier."
|
|
179
|
+
},
|
|
180
|
+
profile: {
|
|
181
|
+
label: "View your profile",
|
|
182
|
+
description: "View your name and profile picture."
|
|
183
|
+
},
|
|
184
|
+
email: {
|
|
185
|
+
label: "View your email address",
|
|
186
|
+
description: "View your email address and whether it is verified."
|
|
187
|
+
},
|
|
188
|
+
offline_access: {
|
|
189
|
+
label: "Maintain access",
|
|
190
|
+
description: "Access your data when you are not actively using the application."
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
function j(e) {
|
|
194
|
+
if (e) try {
|
|
195
|
+
let t = new URL(e);
|
|
196
|
+
return t.protocol === "https:" || t.protocol === "http:" ? t.href : void 0;
|
|
197
|
+
} catch {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function M(e) {
|
|
202
|
+
let t = new URLSearchParams(e);
|
|
203
|
+
return {
|
|
204
|
+
clientId: t.get("client_id")?.trim() || void 0,
|
|
205
|
+
scopes: Array.from(new Set((t.get("scope") ?? "").split(/\s+/).map((e) => e.trim()).filter(Boolean)))
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
var N = n("oauthProvider", (e = {}) => ({
|
|
209
|
+
localization: {
|
|
210
|
+
...O,
|
|
211
|
+
...e.localization
|
|
212
|
+
},
|
|
213
|
+
scopeMetadata: {
|
|
214
|
+
...A,
|
|
215
|
+
...e.scopeMetadata
|
|
216
|
+
},
|
|
217
|
+
viewPaths: { auth: { oauthConsent: e.path ?? "consent" } }
|
|
218
|
+
})), P = {
|
|
219
|
+
all: ["auth", "oauthProvider"],
|
|
220
|
+
publicClients: [
|
|
221
|
+
"auth",
|
|
222
|
+
"oauthProvider",
|
|
223
|
+
"publicClient"
|
|
224
|
+
],
|
|
225
|
+
publicClient: (e) => [...P.publicClients, e ?? null]
|
|
226
|
+
}, F = {
|
|
97
227
|
accept: "Accept",
|
|
98
228
|
accepted: "Accepted",
|
|
99
229
|
actions: "Actions",
|
|
@@ -150,7 +280,7 @@ var r = {
|
|
|
150
280
|
status: "Status",
|
|
151
281
|
uploadLogo: "Upload logo",
|
|
152
282
|
userInvitationsEmptyDescription: "Invitations to join an organization will show up here."
|
|
153
|
-
},
|
|
283
|
+
}, I = {
|
|
154
284
|
all: ["auth", "organization"],
|
|
155
285
|
create: [
|
|
156
286
|
"auth",
|
|
@@ -212,9 +342,9 @@ var r = {
|
|
|
212
342
|
"organization",
|
|
213
343
|
"checkSlug"
|
|
214
344
|
]
|
|
215
|
-
},
|
|
345
|
+
}, L = n("organization", (e = {}) => {
|
|
216
346
|
let n = {
|
|
217
|
-
...
|
|
347
|
+
...F,
|
|
218
348
|
...e.localization
|
|
219
349
|
};
|
|
220
350
|
return {
|
|
@@ -242,38 +372,38 @@ var r = {
|
|
|
242
372
|
}
|
|
243
373
|
}
|
|
244
374
|
};
|
|
245
|
-
}),
|
|
375
|
+
}), R = {
|
|
246
376
|
all: (t) => [...e.user(t), "organization"],
|
|
247
|
-
lists: (e) => [...
|
|
248
|
-
list: (e, t) => [...
|
|
249
|
-
fullDetails: (e) => [...
|
|
250
|
-
fullDetail: (e, t) => [...
|
|
251
|
-
activeOrganizations: (e) => [...
|
|
252
|
-
activeOrganization: (e, t) => [...
|
|
377
|
+
lists: (e) => [...R.all(e), "list"],
|
|
378
|
+
list: (e, t) => [...R.lists(e), t ?? null],
|
|
379
|
+
fullDetails: (e) => [...R.all(e), "fullDetails"],
|
|
380
|
+
fullDetail: (e, t) => [...R.fullDetails(e), t ?? null],
|
|
381
|
+
activeOrganizations: (e) => [...R.all(e), "active"],
|
|
382
|
+
activeOrganization: (e, t) => [...R.activeOrganizations(e), t ?? null],
|
|
253
383
|
members: {
|
|
254
|
-
all: (e) => [...
|
|
255
|
-
lists: (e) => [...
|
|
256
|
-
list: (e, t) => [...
|
|
384
|
+
all: (e) => [...R.all(e), "members"],
|
|
385
|
+
lists: (e) => [...R.members.all(e), "list"],
|
|
386
|
+
list: (e, t) => [...R.members.lists(e), t ?? null]
|
|
257
387
|
},
|
|
258
388
|
invitations: {
|
|
259
|
-
all: (e) => [...
|
|
260
|
-
lists: (e) => [...
|
|
261
|
-
list: (e, t) => [...
|
|
389
|
+
all: (e) => [...R.all(e), "invitations"],
|
|
390
|
+
lists: (e) => [...R.invitations.all(e), "list"],
|
|
391
|
+
list: (e, t) => [...R.invitations.lists(e), t ?? null]
|
|
262
392
|
},
|
|
263
393
|
userInvitations: {
|
|
264
|
-
all: (e) => [...
|
|
265
|
-
lists: (e) => [...
|
|
266
|
-
list: (e, t) => [...
|
|
394
|
+
all: (e) => [...R.all(e), "userInvitations"],
|
|
395
|
+
lists: (e) => [...R.userInvitations.all(e), "list"],
|
|
396
|
+
list: (e, t) => [...R.userInvitations.lists(e), t ?? null]
|
|
267
397
|
},
|
|
268
398
|
permissions: {
|
|
269
|
-
all: (e) => [...
|
|
399
|
+
all: (e) => [...R.all(e), "permissions"],
|
|
270
400
|
has: (e, t) => [
|
|
271
|
-
...
|
|
401
|
+
...R.permissions.all(e),
|
|
272
402
|
"has",
|
|
273
403
|
t ?? null
|
|
274
404
|
]
|
|
275
405
|
}
|
|
276
|
-
},
|
|
406
|
+
}, z = {
|
|
277
407
|
passkey: "Passkey",
|
|
278
408
|
addPasskey: "Add passkey",
|
|
279
409
|
deletePasskey: "Delete passkey {{name}}",
|
|
@@ -283,7 +413,7 @@ var r = {
|
|
|
283
413
|
passkeysDescription: "Create a passkey to securely access your account.",
|
|
284
414
|
noPasskeys: "No passkeys",
|
|
285
415
|
name: "Name"
|
|
286
|
-
},
|
|
416
|
+
}, B = {
|
|
287
417
|
signIn: [
|
|
288
418
|
"auth",
|
|
289
419
|
"signIn",
|
|
@@ -299,22 +429,22 @@ var r = {
|
|
|
299
429
|
"passkey",
|
|
300
430
|
"deletePasskey"
|
|
301
431
|
]
|
|
302
|
-
},
|
|
303
|
-
...
|
|
432
|
+
}, V = n("passkey", (e = {}) => ({ localization: {
|
|
433
|
+
...z,
|
|
304
434
|
...e.localization
|
|
305
|
-
} })),
|
|
435
|
+
} })), H = {
|
|
306
436
|
all: (t) => [...e.user(t), "passkey"],
|
|
307
|
-
lists: (e) => [...
|
|
308
|
-
list: (e, t) => [...
|
|
309
|
-
},
|
|
437
|
+
lists: (e) => [...H.all(e), "list"],
|
|
438
|
+
list: (e, t) => [...H.lists(e), t ?? null]
|
|
439
|
+
}, U = {
|
|
310
440
|
appearance: "Appearance",
|
|
311
441
|
theme: "Theme",
|
|
312
442
|
system: "System",
|
|
313
443
|
light: "Light",
|
|
314
444
|
dark: "Dark"
|
|
315
|
-
},
|
|
445
|
+
}, W = n("theme", (e) => ({
|
|
316
446
|
localization: {
|
|
317
|
-
...
|
|
447
|
+
...U,
|
|
318
448
|
...e.localization
|
|
319
449
|
},
|
|
320
450
|
theme: e.theme ?? "system",
|
|
@@ -324,7 +454,7 @@ var r = {
|
|
|
324
454
|
"light",
|
|
325
455
|
"dark"
|
|
326
456
|
]
|
|
327
|
-
})),
|
|
457
|
+
})), G = {
|
|
328
458
|
username: "Username",
|
|
329
459
|
usernamePlaceholder: "Username",
|
|
330
460
|
usernameOrEmailPlaceholder: "Username or email",
|
|
@@ -332,16 +462,16 @@ var r = {
|
|
|
332
462
|
usernameTaken: "Username is already taken. Please try another.",
|
|
333
463
|
displayUsername: "Display Username",
|
|
334
464
|
displayUsernamePlaceholder: "Display Username"
|
|
335
|
-
},
|
|
465
|
+
}, K = {
|
|
336
466
|
signIn: [
|
|
337
467
|
"auth",
|
|
338
468
|
"signIn",
|
|
339
469
|
"username"
|
|
340
470
|
],
|
|
341
471
|
isUsernameAvailable: ["auth", "isUsernameAvailable"]
|
|
342
|
-
},
|
|
472
|
+
}, q = n("username", (e = {}) => {
|
|
343
473
|
let t = e.minUsernameLength ?? 3, n = e.maxUsernameLength ?? 30, r = {
|
|
344
|
-
...
|
|
474
|
+
...G,
|
|
345
475
|
...e.localization
|
|
346
476
|
};
|
|
347
477
|
return {
|
|
@@ -369,4 +499,4 @@ var r = {
|
|
|
369
499
|
};
|
|
370
500
|
});
|
|
371
501
|
//#endregion
|
|
372
|
-
export { r as
|
|
502
|
+
export { r as adminLocalization, i as adminMutationKeys, o as adminPlugin, s as apiKeyLocalization, c as apiKeyMutationKeys, l as apiKeyPlugin, u as apiKeyQueryKeys, d as deleteUserLocalization, f as deleteUserMutationKeys, p as deleteUserPlugin, m as deviceAuthorizationLocalization, h as deviceAuthorizationMutationKeys, v as deviceAuthorizationPlugin, a as isImpersonatingSession, y as lastLoginMethodLocalization, b as lastLoginMethodPlugin, x as magicLinkLocalization, S as magicLinkMutationKeys, C as magicLinkPlugin, w as multiSessionLocalization, T as multiSessionMutationKeys, E as multiSessionPlugin, D as multiSessionQueryKeys, O as oauthProviderLocalization, k as oauthProviderMutationKeys, N as oauthProviderPlugin, P as oauthProviderQueryKeys, A as oauthProviderScopeMetadata, F as organizationLocalization, I as organizationMutationKeys, L as organizationPlugin, R as organizationQueryKeys, M as parseOAuthAuthorizationRequest, z as passkeyLocalization, B as passkeyMutationKeys, V as passkeyPlugin, H as passkeyQueryKeys, j as sanitizeOAuthClientUrl, U as themeLocalization, W as themePlugin, G as usernameLocalization, K as usernameMutationKeys, q as usernamePlugin };
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from "./config"
|
|
|
2
2
|
export * from "./lib/auth-mutation-keys"
|
|
3
3
|
export * from "./lib/auth-plugin"
|
|
4
4
|
export * from "./lib/auth-query-keys"
|
|
5
|
+
export * from "./lib/auth-redirect"
|
|
5
6
|
export * from "./lib/base-paths"
|
|
6
7
|
export * from "./lib/create-auth-plugin"
|
|
7
8
|
export * from "./lib/deep-partial"
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
* package the mutation options factory came from.
|
|
20
20
|
*
|
|
21
21
|
* Plugin-specific mutation keys live alongside their plugin (e.g.
|
|
22
|
-
* `apiKeyMutationKeys`, `
|
|
23
|
-
* `
|
|
24
|
-
* `deleteUserMutationKeys`).
|
|
25
|
-
*
|
|
22
|
+
* `apiKeyMutationKeys`, `deviceAuthorizationMutationKeys`,
|
|
23
|
+
* `organizationMutationKeys`, `passkeyMutationKeys`, `magicLinkMutationKeys`,
|
|
24
|
+
* `multiSessionMutationKeys`, `usernameMutationKeys`, `deleteUserMutationKeys`).
|
|
25
|
+
* Plugin-contributed sign-in strategies stay under the shared
|
|
26
|
+
* `["auth", "signIn", ...]` namespace so
|
|
26
27
|
* `useIsMutating({ mutationKey: authMutationKeys.signIn.all })` still
|
|
27
28
|
* matches them.
|
|
28
29
|
*
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const ABSOLUTE_HTTP_URL = /^https?:\/\//i
|
|
2
|
+
|
|
3
|
+
function hasUnsafeRedirectCharacters(value: string): boolean {
|
|
4
|
+
for (const character of value) {
|
|
5
|
+
const codePoint = character.codePointAt(0)
|
|
6
|
+
if (
|
|
7
|
+
character === "\\" ||
|
|
8
|
+
codePoint === undefined ||
|
|
9
|
+
codePoint <= 31 ||
|
|
10
|
+
codePoint === 127
|
|
11
|
+
) {
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Normalize a redirect target to a same-origin path.
|
|
21
|
+
*
|
|
22
|
+
* Root-relative paths and same-origin HTTP(S) URLs are accepted. Invalid,
|
|
23
|
+
* cross-origin, protocol-relative, and non-HTTP targets fall back to `/`.
|
|
24
|
+
*
|
|
25
|
+
* @param redirectTo - Requested redirect target
|
|
26
|
+
* @param origin - Origin used to validate and normalize the target
|
|
27
|
+
* @returns A same-origin path including its query string and hash
|
|
28
|
+
*/
|
|
29
|
+
export function getSafeRedirectTo(
|
|
30
|
+
redirectTo: string | null | undefined,
|
|
31
|
+
origin: string
|
|
32
|
+
): string {
|
|
33
|
+
if (!redirectTo || hasUnsafeRedirectCharacters(redirectTo)) return "/"
|
|
34
|
+
|
|
35
|
+
const target = redirectTo.trim()
|
|
36
|
+
if (
|
|
37
|
+
!target ||
|
|
38
|
+
target.startsWith("//") ||
|
|
39
|
+
(!target.startsWith("/") && !ABSOLUTE_HTTP_URL.test(target))
|
|
40
|
+
) {
|
|
41
|
+
return "/"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const baseURL = new URL(origin)
|
|
46
|
+
const targetURL = new URL(target, baseURL)
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
targetURL.origin !== baseURL.origin ||
|
|
50
|
+
targetURL.username ||
|
|
51
|
+
targetURL.password
|
|
52
|
+
) {
|
|
53
|
+
return "/"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return `${targetURL.pathname}${targetURL.search}${targetURL.hash}`
|
|
57
|
+
} catch {
|
|
58
|
+
return "/"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type AuthRedirectAction =
|
|
63
|
+
| { type: "redirect"; to: string }
|
|
64
|
+
| { type: "signIn"; to: string }
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the next action for the authenticated redirect view.
|
|
68
|
+
*
|
|
69
|
+
* Signed-in users continue to the validated target. Signed-out users are sent
|
|
70
|
+
* to sign in with the current redirect-view URL preserved, allowing the view
|
|
71
|
+
* to perform a full-page redirect after authentication.
|
|
72
|
+
*
|
|
73
|
+
* @param currentURL - Current redirect-view URL
|
|
74
|
+
* @param authenticated - Whether the current user has a session
|
|
75
|
+
* @param signInPath - Same-origin path to the sign-in view
|
|
76
|
+
* @returns The redirect or sign-in action to perform
|
|
77
|
+
*/
|
|
78
|
+
export function getAuthRedirectAction(
|
|
79
|
+
currentURL: URL,
|
|
80
|
+
authenticated: boolean,
|
|
81
|
+
signInPath: string
|
|
82
|
+
): AuthRedirectAction {
|
|
83
|
+
const requestedTarget = getSafeRedirectTo(
|
|
84
|
+
currentURL.searchParams.get("redirectTo"),
|
|
85
|
+
currentURL.origin
|
|
86
|
+
)
|
|
87
|
+
const targetURL = new URL(requestedTarget, currentURL.origin)
|
|
88
|
+
const redirectTo =
|
|
89
|
+
targetURL.pathname === currentURL.pathname ? "/" : requestedTarget
|
|
90
|
+
|
|
91
|
+
if (authenticated) {
|
|
92
|
+
return { type: "redirect", to: redirectTo }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const signInURL = new URL(signInPath, currentURL.origin)
|
|
96
|
+
signInURL.searchParams.set(
|
|
97
|
+
"redirectTo",
|
|
98
|
+
`${currentURL.pathname}${currentURL.search}${currentURL.hash}`
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
type: "signIn",
|
|
103
|
+
to: `${signInURL.pathname}${signInURL.search}${signInURL.hash}`
|
|
104
|
+
}
|
|
105
|
+
}
|
package/src/lib/view-paths.ts
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* View path segments for authentication routes.
|
|
3
3
|
*/
|
|
4
4
|
export interface AuthViewPaths {
|
|
5
|
+
/**
|
|
6
|
+
* Path segment for the authenticated redirect view
|
|
7
|
+
* @default "redirect"
|
|
8
|
+
*/
|
|
9
|
+
redirect: string
|
|
5
10
|
/**
|
|
6
11
|
* Path segment for the sign-in view
|
|
7
12
|
* @default "sign-in"
|
|
@@ -67,6 +72,7 @@ export type ViewPaths = {
|
|
|
67
72
|
|
|
68
73
|
export const viewPaths: ViewPaths = {
|
|
69
74
|
auth: {
|
|
75
|
+
redirect: "redirect",
|
|
70
76
|
signIn: "sign-in",
|
|
71
77
|
signUp: "sign-up",
|
|
72
78
|
forgotPassword: "forgot-password",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutation keys contributed by the admin plugin.
|
|
3
|
+
*/
|
|
4
|
+
export const adminMutationKeys = {
|
|
5
|
+
/** Root key for every admin mutation. */
|
|
6
|
+
all: ["auth", "admin"] as const,
|
|
7
|
+
/** Key for `admin.stopImpersonating`. */
|
|
8
|
+
stopImpersonating: ["auth", "admin", "stopImpersonating"] as const
|
|
9
|
+
} as const
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createAuthPlugin } from "../../lib/create-auth-plugin"
|
|
2
|
+
import { type AdminLocalization, adminLocalization } from "./admin-localization"
|
|
3
|
+
|
|
4
|
+
export type AdminPluginOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Override the plugin's default localization strings.
|
|
7
|
+
* @remarks `AdminLocalization`
|
|
8
|
+
*/
|
|
9
|
+
localization?: Partial<AdminLocalization>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ImpersonatingSession = {
|
|
13
|
+
session: {
|
|
14
|
+
impersonatedBy: string
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Check whether a Better Auth session belongs to an impersonated user.
|
|
20
|
+
*/
|
|
21
|
+
export function isImpersonatingSession(
|
|
22
|
+
session: unknown
|
|
23
|
+
): session is ImpersonatingSession {
|
|
24
|
+
if (
|
|
25
|
+
!session ||
|
|
26
|
+
typeof session !== "object" ||
|
|
27
|
+
!("session" in session) ||
|
|
28
|
+
!session.session ||
|
|
29
|
+
typeof session.session !== "object" ||
|
|
30
|
+
!("impersonatedBy" in session.session)
|
|
31
|
+
) {
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
typeof session.session.impersonatedBy === "string" &&
|
|
37
|
+
session.session.impersonatedBy.length > 0
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Adds UI integrations for Better Auth's admin plugin.
|
|
43
|
+
*
|
|
44
|
+
* Pair this UI plugin with Better Auth's `admin()` server plugin and
|
|
45
|
+
* `adminClient()` client plugin.
|
|
46
|
+
*/
|
|
47
|
+
export const adminPlugin = createAuthPlugin(
|
|
48
|
+
"admin",
|
|
49
|
+
(options: AdminPluginOptions = {}) => ({
|
|
50
|
+
localization: { ...adminLocalization, ...options.localization }
|
|
51
|
+
})
|
|
52
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const deviceAuthorizationLocalization = {
|
|
2
|
+
/** @remarks `"Device Authorization"` */
|
|
3
|
+
deviceAuthorization: "Device Authorization",
|
|
4
|
+
/** @remarks `"Enter the code displayed on your device."` */
|
|
5
|
+
deviceAuthorizationDescription: "Enter the code displayed on your device.",
|
|
6
|
+
/** @remarks `"Device code"` */
|
|
7
|
+
deviceCode: "Device code",
|
|
8
|
+
/** @remarks `"The code is invalid or has expired."` */
|
|
9
|
+
invalidDeviceCode: "The code is invalid or has expired.",
|
|
10
|
+
/** @remarks `"Continue"` */
|
|
11
|
+
continue: "Continue",
|
|
12
|
+
/** @remarks `"Approve Device"` */
|
|
13
|
+
approveDevice: "Approve Device",
|
|
14
|
+
/** @remarks `"A device is requesting access to your account."` */
|
|
15
|
+
approveDeviceDescription: "A device is requesting access to your account.",
|
|
16
|
+
/** @remarks `"Signed in as"` */
|
|
17
|
+
signedInAs: "Signed in as",
|
|
18
|
+
/** @remarks `"Approve"` */
|
|
19
|
+
approve: "Approve",
|
|
20
|
+
/** @remarks `"Deny"` */
|
|
21
|
+
deny: "Deny",
|
|
22
|
+
/** @remarks `"Device Approved"` */
|
|
23
|
+
deviceApproved: "Device Approved",
|
|
24
|
+
/** @remarks `"The device can now access your account. You can return to it and continue."` */
|
|
25
|
+
deviceApprovedDescription:
|
|
26
|
+
"The device can now access your account. You can return to it and continue.",
|
|
27
|
+
/** @remarks `"Device Denied"` */
|
|
28
|
+
deviceDenied: "Device Denied",
|
|
29
|
+
/** @remarks `"The device was not granted access to your account."` */
|
|
30
|
+
deviceDeniedDescription: "The device was not granted access to your account.",
|
|
31
|
+
/** @remarks `"Return to application"` */
|
|
32
|
+
returnToApplication: "Return to application"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type DeviceAuthorizationLocalization =
|
|
36
|
+
typeof deviceAuthorizationLocalization
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutation keys contributed by the device-authorization plugin.
|
|
3
|
+
*
|
|
4
|
+
* All keys live under the shared `["auth"]` namespace so global auth
|
|
5
|
+
* mutation observers handle errors consistently.
|
|
6
|
+
*/
|
|
7
|
+
export const deviceAuthorizationMutationKeys = {
|
|
8
|
+
/** Prefix matching every device-authorization mutation. */
|
|
9
|
+
all: ["auth", "deviceAuthorization"] as const,
|
|
10
|
+
/** Key for verifying and claiming a user code. */
|
|
11
|
+
verify: ["auth", "deviceAuthorization", "verify"] as const,
|
|
12
|
+
/** Key for approving a pending device request. */
|
|
13
|
+
approve: ["auth", "deviceAuthorization", "approve"] as const,
|
|
14
|
+
/** Key for denying a pending device request. */
|
|
15
|
+
deny: ["auth", "deviceAuthorization", "deny"] as const
|
|
16
|
+
} as const
|