better-auth 0.0.2-beta.7 → 0.0.2
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/access.d.ts +4 -0
- package/dist/access.js +126 -0
- package/dist/access.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +553 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/plugins.d.ts +2436 -0
- package/dist/client/plugins.js +411 -0
- package/dist/client/plugins.js.map +1 -0
- package/dist/client-A2Mt04KQ.d.ts +3503 -0
- package/dist/client.d.ts +1433 -0
- package/dist/client.js +693 -0
- package/dist/client.js.map +1 -0
- package/dist/helper-B5_2Vzba.d.ts +14 -0
- package/dist/index-Dg4eEXZW.d.ts +24 -0
- package/dist/index-W5nXvJ-p.d.ts +1498 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2195 -1191
- package/dist/index.js.map +1 -1
- package/dist/next-js.d.ts +14 -0
- package/dist/next-js.js +14 -0
- package/dist/next-js.js.map +1 -0
- package/dist/plugins.d.ts +892 -49
- package/dist/plugins.js +3951 -253
- package/dist/plugins.js.map +1 -1
- package/dist/preact.d.ts +8 -0
- package/dist/preact.js +294 -0
- package/dist/preact.js.map +1 -0
- package/dist/react.d.ts +14 -0
- package/dist/react.js +314 -0
- package/dist/react.js.map +1 -0
- package/dist/schema-BOszzrbQ.d.ts +792 -0
- package/dist/social.d.ts +4 -0
- package/dist/social.js +509 -0
- package/dist/social.js.map +1 -0
- package/dist/solid-start.d.ts +18 -0
- package/dist/solid-start.js +14 -0
- package/dist/solid-start.js.map +1 -0
- package/dist/solid.d.ts +2790 -0
- package/dist/solid.js +306 -0
- package/dist/solid.js.map +1 -0
- package/dist/statement-COylZd3J.d.ts +81 -0
- package/dist/svelte-kit.d.ts +10 -7
- package/dist/svelte-kit.js +12 -17
- package/dist/svelte-kit.js.map +1 -1
- package/dist/svelte.d.ts +2791 -0
- package/dist/svelte.js +304 -0
- package/dist/svelte.js.map +1 -0
- package/dist/type-DbMyI3b5.d.ts +5724 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/vue.d.ts +14 -0
- package/dist/vue.js +311 -0
- package/dist/vue.js.map +1 -0
- package/package.json +80 -54
- package/LICENSE +0 -21
- package/dist/actions.d.ts +0 -33
- package/dist/actions.js +0 -1373
- package/dist/actions.js.map +0 -1
- package/dist/adapters/drizzle-adapter.d.ts +0 -10
- package/dist/adapters/drizzle-adapter.js +0 -1095
- package/dist/adapters/drizzle-adapter.js.map +0 -1
- package/dist/adapters/memory.d.ts +0 -8
- package/dist/adapters/memory.js +0 -136
- package/dist/adapters/memory.js.map +0 -1
- package/dist/adapters/mongodb-adapter.d.ts +0 -9
- package/dist/adapters/mongodb-adapter.js +0 -97
- package/dist/adapters/mongodb-adapter.js.map +0 -1
- package/dist/adapters/prisma-adapter.d.ts +0 -7
- package/dist/adapters/prisma-adapter.js +0 -144
- package/dist/adapters/prisma-adapter.js.map +0 -1
- package/dist/adapters/redis-adapter.d.ts +0 -7
- package/dist/adapters/redis-adapter.js +0 -65
- package/dist/adapters/redis-adapter.js.map +0 -1
- package/dist/adapters.d.ts +0 -3
- package/dist/adapters.js +0 -206
- package/dist/adapters.js.map +0 -1
- package/dist/h3.d.ts +0 -10
- package/dist/h3.js +0 -326
- package/dist/h3.js.map +0 -1
- package/dist/hono.d.ts +0 -10
- package/dist/hono.js +0 -25
- package/dist/hono.js.map +0 -1
- package/dist/index-UcTu1vUg.d.ts +0 -107
- package/dist/next.d.ts +0 -17
- package/dist/next.js +0 -26
- package/dist/next.js.map +0 -1
- package/dist/options-CH15FEBw.d.ts +0 -1562
- package/dist/providers.d.ts +0 -3
- package/dist/providers.js +0 -653
- package/dist/providers.js.map +0 -1
- package/dist/routes/session.d.ts +0 -39
- package/dist/routes/session.js +0 -128
- package/dist/routes/session.js.map +0 -1
- package/dist/types-DAxaMWCy.d.ts +0 -136
package/dist/actions.js
DELETED
|
@@ -1,1373 +0,0 @@
|
|
|
1
|
-
// src/crypto/random.ts
|
|
2
|
-
function generateRandomString(size) {
|
|
3
|
-
const i2hex = (i) => `0${i.toString(16)}`.slice(-2);
|
|
4
|
-
const r = (a, i) => a + i2hex(i);
|
|
5
|
-
const bytes = crypto.getRandomValues(new Uint8Array(size));
|
|
6
|
-
return Array.from(bytes).reduce(r, "");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// src/utils/time.ts
|
|
10
|
-
var timeSpan = (span) => {
|
|
11
|
-
const [time, unit] = span;
|
|
12
|
-
const timeInMs = Number.parseInt(time) * 1e3;
|
|
13
|
-
switch (unit) {
|
|
14
|
-
case "s":
|
|
15
|
-
return timeInMs;
|
|
16
|
-
case "m":
|
|
17
|
-
return timeInMs * 60;
|
|
18
|
-
case "hr":
|
|
19
|
-
return timeInMs * 60 * 60;
|
|
20
|
-
case "d":
|
|
21
|
-
return timeInMs * 60 * 60 * 24;
|
|
22
|
-
case "w":
|
|
23
|
-
return timeInMs * 60 * 60 * 24 * 7;
|
|
24
|
-
default:
|
|
25
|
-
return 0;
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
var getDate = (span) => {
|
|
29
|
-
const sec = typeof span === "number" ? span : timeSpan(span);
|
|
30
|
-
const date = /* @__PURE__ */ new Date();
|
|
31
|
-
return new Date(date.getTime() + sec);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// src/adapters/internal-adapter.ts
|
|
35
|
-
var createInternalAdapter = (db) => {
|
|
36
|
-
return {
|
|
37
|
-
createSession: async (userId, context) => {
|
|
38
|
-
if (context.sessionAdapter) {
|
|
39
|
-
return context.sessionAdapter.create({
|
|
40
|
-
userId,
|
|
41
|
-
expiresAt: new Date(Date.now() + context.session.expiresIn)
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
const session2 = await db.create({
|
|
45
|
-
model: context.session.modelName,
|
|
46
|
-
data: {
|
|
47
|
-
id: generateRandomString(32),
|
|
48
|
-
userId,
|
|
49
|
-
expiresAt: db.config?.dateFormat === "number" ? Date.now() + context.session.expiresIn : new Date(Date.now() + context.session.expiresIn)
|
|
50
|
-
},
|
|
51
|
-
select: context.session.selectFields
|
|
52
|
-
});
|
|
53
|
-
return session2;
|
|
54
|
-
},
|
|
55
|
-
updateSession: async (session2, context) => {
|
|
56
|
-
const updateDate = context.session.updateAge === 0 ? 0 : getDate(context.session.updateAge).valueOf();
|
|
57
|
-
const maxAge = getDate(context.session.expiresIn);
|
|
58
|
-
const shouldBeUpdated = session2.expiresAt.valueOf() - maxAge.valueOf() + updateDate <= Date.now();
|
|
59
|
-
if (shouldBeUpdated) {
|
|
60
|
-
if (context.sessionAdapter) {
|
|
61
|
-
return context.sessionAdapter.update({
|
|
62
|
-
id: session2.id,
|
|
63
|
-
userId: session2.userId,
|
|
64
|
-
expiresAt: new Date(Date.now() + context.session.expiresIn)
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
const updatedSession = await db.update({
|
|
68
|
-
model: context.session.modelName,
|
|
69
|
-
where: [
|
|
70
|
-
{
|
|
71
|
-
field: "id",
|
|
72
|
-
value: session2.id
|
|
73
|
-
}
|
|
74
|
-
],
|
|
75
|
-
update: {
|
|
76
|
-
expiresAt: db.config?.dateFormat === "number" ? Date.now() + context.session.expiresIn : new Date(Date.now() + context.session.expiresIn)
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
return updatedSession;
|
|
80
|
-
}
|
|
81
|
-
return session2;
|
|
82
|
-
},
|
|
83
|
-
deleteSession: async (id, context) => {
|
|
84
|
-
const session2 = await db.delete({
|
|
85
|
-
model: context.session.modelName,
|
|
86
|
-
where: [
|
|
87
|
-
{
|
|
88
|
-
field: "id",
|
|
89
|
-
value: id
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
});
|
|
93
|
-
return session2;
|
|
94
|
-
},
|
|
95
|
-
createUser: async (data, context) => {
|
|
96
|
-
const user = await db.create({
|
|
97
|
-
model: context.user.modelName,
|
|
98
|
-
data: {
|
|
99
|
-
id: generateRandomString(32),
|
|
100
|
-
...data.user
|
|
101
|
-
},
|
|
102
|
-
select: context.user.selectFields
|
|
103
|
-
});
|
|
104
|
-
const account = await db.create({
|
|
105
|
-
model: context.account.modelName,
|
|
106
|
-
data: {
|
|
107
|
-
...data.account,
|
|
108
|
-
userId: user.id,
|
|
109
|
-
providerId: data.account.providerId.toString(),
|
|
110
|
-
accountId: data.account.accountId.toString()
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
return { user, account };
|
|
114
|
-
},
|
|
115
|
-
updateUserByEmail: async (email, data, context) => {
|
|
116
|
-
const user = await db.update({
|
|
117
|
-
model: context.user.modelName,
|
|
118
|
-
where: [
|
|
119
|
-
{
|
|
120
|
-
field: "email",
|
|
121
|
-
value: email
|
|
122
|
-
}
|
|
123
|
-
],
|
|
124
|
-
update: data
|
|
125
|
-
});
|
|
126
|
-
return user;
|
|
127
|
-
},
|
|
128
|
-
findUserByEmail: async (email, context) => {
|
|
129
|
-
const user = await db.findOne({
|
|
130
|
-
model: context.user.modelName,
|
|
131
|
-
where: [
|
|
132
|
-
{
|
|
133
|
-
field: "email",
|
|
134
|
-
value: email
|
|
135
|
-
}
|
|
136
|
-
],
|
|
137
|
-
select: context.user.selectFields
|
|
138
|
-
});
|
|
139
|
-
return user;
|
|
140
|
-
},
|
|
141
|
-
findSession: async (id, context) => {
|
|
142
|
-
if (context.sessionAdapter) {
|
|
143
|
-
return context.sessionAdapter.findOne({
|
|
144
|
-
userId: id
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
const session2 = await db.findOne({
|
|
148
|
-
model: context.session.modelName,
|
|
149
|
-
where: [
|
|
150
|
-
{
|
|
151
|
-
field: "id",
|
|
152
|
-
value: id
|
|
153
|
-
}
|
|
154
|
-
],
|
|
155
|
-
select: context.session.selectFields
|
|
156
|
-
});
|
|
157
|
-
return session2;
|
|
158
|
-
},
|
|
159
|
-
findUserById: async (id, context) => {
|
|
160
|
-
const user = await db.findOne({
|
|
161
|
-
model: context.user.modelName,
|
|
162
|
-
where: [
|
|
163
|
-
{
|
|
164
|
-
field: "id",
|
|
165
|
-
value: id
|
|
166
|
-
}
|
|
167
|
-
],
|
|
168
|
-
select: context.user.selectFields
|
|
169
|
-
});
|
|
170
|
-
return user;
|
|
171
|
-
},
|
|
172
|
-
findAccount: async (input, context) => {
|
|
173
|
-
const account = await db.findOne({
|
|
174
|
-
model: context.account.modelName,
|
|
175
|
-
where: [
|
|
176
|
-
{
|
|
177
|
-
field: "providerId",
|
|
178
|
-
value: input.providerId.toString()
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
field: "accountId",
|
|
182
|
-
value: input.accountId.toString()
|
|
183
|
-
}
|
|
184
|
-
],
|
|
185
|
-
select: context.account.selectFields
|
|
186
|
-
});
|
|
187
|
-
return account;
|
|
188
|
-
},
|
|
189
|
-
linkAccount: async (input, context) => {
|
|
190
|
-
const { userId, providerId, accountId } = input;
|
|
191
|
-
const account = await db.create({
|
|
192
|
-
model: context.account.modelName,
|
|
193
|
-
data: {
|
|
194
|
-
userId,
|
|
195
|
-
providerId: providerId.toString(),
|
|
196
|
-
accountId: accountId.toString()
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
return account;
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
// src/adapters/utils.ts
|
|
205
|
-
import { z } from "zod";
|
|
206
|
-
function toInternalFields(fields) {
|
|
207
|
-
const internalFields = {};
|
|
208
|
-
for (const field in fields) {
|
|
209
|
-
const { type, required, returned, hashValue, transform } = fields[field];
|
|
210
|
-
internalFields[field] = {
|
|
211
|
-
required: required ?? false,
|
|
212
|
-
returned: returned ?? true,
|
|
213
|
-
hashValue: hashValue ?? false,
|
|
214
|
-
validator: z[type]().transform(transform || ((x) => x))
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
return internalFields;
|
|
218
|
-
}
|
|
219
|
-
function getSelectFields(fields, table) {
|
|
220
|
-
const select = Object.keys(fields).filter((column) => {
|
|
221
|
-
return fields[column]?.returned !== false;
|
|
222
|
-
});
|
|
223
|
-
const defaultSelect = {
|
|
224
|
-
session: ["id", "userId", "expiresAt"],
|
|
225
|
-
user: ["id", "email", "emailVerified"],
|
|
226
|
-
account: ["providerId", "accountId", "userId"]
|
|
227
|
-
};
|
|
228
|
-
return [...defaultSelect[table], ...select];
|
|
229
|
-
}
|
|
230
|
-
var parseUser = (data, context) => {
|
|
231
|
-
const user = Object.keys(data).map((key) => {
|
|
232
|
-
const parsed = context.user.fields[key]?.validator.safeParse(data?.[key]);
|
|
233
|
-
return { key, value: parsed?.success ? parsed.data : data?.[key] };
|
|
234
|
-
}).reduce(
|
|
235
|
-
(acc, { key, value }) => {
|
|
236
|
-
acc[key] = value;
|
|
237
|
-
return acc;
|
|
238
|
-
},
|
|
239
|
-
{}
|
|
240
|
-
);
|
|
241
|
-
return user;
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
// src/cookies/index.ts
|
|
245
|
-
function serialize(name, value, attributes) {
|
|
246
|
-
const keyValueEntries = [];
|
|
247
|
-
keyValueEntries.push([encodeURIComponent(name), encodeURIComponent(value)]);
|
|
248
|
-
if (attributes?.domain !== void 0) {
|
|
249
|
-
keyValueEntries.push(["Domain", attributes.domain]);
|
|
250
|
-
}
|
|
251
|
-
if (attributes?.expires !== void 0) {
|
|
252
|
-
keyValueEntries.push(["Expires", attributes.expires.toUTCString()]);
|
|
253
|
-
}
|
|
254
|
-
if (attributes?.httpOnly) {
|
|
255
|
-
keyValueEntries.push(["HttpOnly"]);
|
|
256
|
-
}
|
|
257
|
-
if (attributes?.maxAge !== void 0) {
|
|
258
|
-
keyValueEntries.push(["Max-Age", attributes.maxAge.toString()]);
|
|
259
|
-
}
|
|
260
|
-
if (attributes?.path !== void 0) {
|
|
261
|
-
keyValueEntries.push(["Path", attributes.path]);
|
|
262
|
-
}
|
|
263
|
-
if (attributes?.sameSite === "lax") {
|
|
264
|
-
keyValueEntries.push(["SameSite", "Lax"]);
|
|
265
|
-
}
|
|
266
|
-
if (attributes?.sameSite === "none") {
|
|
267
|
-
keyValueEntries.push(["SameSite", "None"]);
|
|
268
|
-
}
|
|
269
|
-
if (attributes?.sameSite === "strict") {
|
|
270
|
-
keyValueEntries.push(["SameSite", "Strict"]);
|
|
271
|
-
}
|
|
272
|
-
if (attributes?.secure) {
|
|
273
|
-
keyValueEntries.push(["Secure"]);
|
|
274
|
-
}
|
|
275
|
-
return keyValueEntries.map((pair) => pair.join("=")).join("; ");
|
|
276
|
-
}
|
|
277
|
-
function parse(header) {
|
|
278
|
-
const cookies = /* @__PURE__ */ new Map();
|
|
279
|
-
const items = header.split("; ");
|
|
280
|
-
for (const item of items) {
|
|
281
|
-
const pair = item.split("=");
|
|
282
|
-
const rawKey = pair[0];
|
|
283
|
-
const rawValue = pair[1] ?? "";
|
|
284
|
-
if (!rawKey)
|
|
285
|
-
continue;
|
|
286
|
-
cookies.set(decodeURIComponent(rawKey), decodeURIComponent(rawValue));
|
|
287
|
-
}
|
|
288
|
-
return cookies;
|
|
289
|
-
}
|
|
290
|
-
var cookieManager = (header) => {
|
|
291
|
-
return {
|
|
292
|
-
set(name, value, options = {}) {
|
|
293
|
-
const cookieStr = serialize(name, value, options);
|
|
294
|
-
header.append("set-cookie", cookieStr);
|
|
295
|
-
},
|
|
296
|
-
get(name) {
|
|
297
|
-
const cookie = header.get("cookie");
|
|
298
|
-
if (!cookie)
|
|
299
|
-
return null;
|
|
300
|
-
const cookies = parse(cookie);
|
|
301
|
-
const value = cookies.get(name);
|
|
302
|
-
return value;
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
};
|
|
306
|
-
function setSessionCookie(context, sessionId) {
|
|
307
|
-
context.request.cookies.set(
|
|
308
|
-
context.cookies.sessionToken.name,
|
|
309
|
-
sessionId,
|
|
310
|
-
context.cookies.sessionToken.options
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
function deleteSessionCooke(context) {
|
|
314
|
-
context.request.cookies.set(context.cookies.sessionToken.name, "", {
|
|
315
|
-
...context.cookies.sessionToken.options,
|
|
316
|
-
maxAge: 0
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// src/cookies/cookies.ts
|
|
321
|
-
function getCookies(options) {
|
|
322
|
-
const secure = !!options.advanced?.useSecureCookies;
|
|
323
|
-
const secureCookiePrefix = secure ? "__Secure-" : "";
|
|
324
|
-
const cookiePrefix = "better-auth";
|
|
325
|
-
return {
|
|
326
|
-
sessionToken: {
|
|
327
|
-
name: `${secureCookiePrefix}${cookiePrefix}.session_token`,
|
|
328
|
-
options: {
|
|
329
|
-
httpOnly: true,
|
|
330
|
-
sameSite: "lax",
|
|
331
|
-
path: "/",
|
|
332
|
-
secure,
|
|
333
|
-
maxAge: options.session?.expiresIn || timeSpan("7d"),
|
|
334
|
-
...options.advanced?.sessionCookie
|
|
335
|
-
}
|
|
336
|
-
},
|
|
337
|
-
csrfToken: {
|
|
338
|
-
name: `${secureCookiePrefix}${cookiePrefix}.csrf_token`,
|
|
339
|
-
options: {
|
|
340
|
-
httpOnly: true,
|
|
341
|
-
sameSite: "lax",
|
|
342
|
-
path: "/",
|
|
343
|
-
secure
|
|
344
|
-
}
|
|
345
|
-
},
|
|
346
|
-
state: {
|
|
347
|
-
name: `${secureCookiePrefix}${cookiePrefix}.state`,
|
|
348
|
-
options: {
|
|
349
|
-
httpOnly: true,
|
|
350
|
-
sameSite: "lax",
|
|
351
|
-
path: "/",
|
|
352
|
-
secure,
|
|
353
|
-
maxAge: 60 * 15
|
|
354
|
-
// 15 minutes in seconds
|
|
355
|
-
}
|
|
356
|
-
},
|
|
357
|
-
pkCodeVerifier: {
|
|
358
|
-
name: `${secureCookiePrefix}${cookiePrefix}.pk_code_verifier`,
|
|
359
|
-
options: {
|
|
360
|
-
httpOnly: true,
|
|
361
|
-
sameSite: "lax",
|
|
362
|
-
path: "/",
|
|
363
|
-
secure,
|
|
364
|
-
maxAge: 60 * 15
|
|
365
|
-
// 15 minutes in seconds
|
|
366
|
-
}
|
|
367
|
-
},
|
|
368
|
-
nonce: {
|
|
369
|
-
name: `${secureCookiePrefix}${cookiePrefix}.nonce`,
|
|
370
|
-
options: {
|
|
371
|
-
httpOnly: true,
|
|
372
|
-
sameSite: "lax",
|
|
373
|
-
path: "/",
|
|
374
|
-
secure,
|
|
375
|
-
maxAge: 60 * 15
|
|
376
|
-
// 15 minutes in seconds
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// src/crypto/hmac.ts
|
|
383
|
-
async function hmac(secretKey, message) {
|
|
384
|
-
const enc = new TextEncoder();
|
|
385
|
-
const algorithm = { name: "HMAC", hash: "SHA-256" };
|
|
386
|
-
const key = await crypto.subtle.importKey(
|
|
387
|
-
"raw",
|
|
388
|
-
enc.encode(secretKey),
|
|
389
|
-
algorithm,
|
|
390
|
-
false,
|
|
391
|
-
["sign", "verify"]
|
|
392
|
-
);
|
|
393
|
-
const signature = await crypto.subtle.sign(
|
|
394
|
-
algorithm.name,
|
|
395
|
-
key,
|
|
396
|
-
enc.encode(message)
|
|
397
|
-
);
|
|
398
|
-
return btoa(String.fromCharCode(...new Uint8Array(signature)));
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// src/plugins/csrf-check.ts
|
|
402
|
-
var csrfHandler = async (context) => {
|
|
403
|
-
const csrfToken = context.request.cookies.get(context.cookies.csrfToken.name);
|
|
404
|
-
if (csrfToken) {
|
|
405
|
-
return {
|
|
406
|
-
status: 200,
|
|
407
|
-
body: {
|
|
408
|
-
csrfToken
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
const token = generateRandomString(32);
|
|
413
|
-
const hash = await hmac(context.secret, token);
|
|
414
|
-
const cookie = `${token}!${hash}`;
|
|
415
|
-
context.request.cookies.set(
|
|
416
|
-
context.cookies.csrfToken.name,
|
|
417
|
-
cookie,
|
|
418
|
-
context.cookies.csrfToken.options
|
|
419
|
-
);
|
|
420
|
-
return {
|
|
421
|
-
status: 200,
|
|
422
|
-
body: {
|
|
423
|
-
csrfToken: cookie
|
|
424
|
-
}
|
|
425
|
-
};
|
|
426
|
-
};
|
|
427
|
-
var CSRFCheckPlugin = () => {
|
|
428
|
-
return {
|
|
429
|
-
id: "csrf",
|
|
430
|
-
name: "CSRF Check",
|
|
431
|
-
version: "1.0.0",
|
|
432
|
-
hooks: {
|
|
433
|
-
matcher: (context) => !context.disableCSRF,
|
|
434
|
-
before: async (context) => {
|
|
435
|
-
const csrfToken = context.request.body.csrfToken;
|
|
436
|
-
const csrfCookie = context.request.cookies.get(
|
|
437
|
-
context.cookies.csrfToken.name
|
|
438
|
-
);
|
|
439
|
-
const [token, hash] = csrfCookie?.split("!") || [null, null];
|
|
440
|
-
if (!csrfToken || !csrfCookie || !token || !hash || csrfCookie !== csrfToken) {
|
|
441
|
-
context.request.cookies.set(context.cookies.csrfToken.name, "", {
|
|
442
|
-
...context.cookies.csrfToken.options,
|
|
443
|
-
maxAge: 0
|
|
444
|
-
});
|
|
445
|
-
return {
|
|
446
|
-
response: {
|
|
447
|
-
status: 403,
|
|
448
|
-
statusText: "Invalid CSRF Token"
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
const expectedHash = await hmac(context.secret, token);
|
|
453
|
-
if (hash !== expectedHash) {
|
|
454
|
-
context.request.cookies.set(context.cookies.csrfToken.name, "", {
|
|
455
|
-
...context.cookies.csrfToken.options,
|
|
456
|
-
maxAge: 0
|
|
457
|
-
});
|
|
458
|
-
return {
|
|
459
|
-
response: {
|
|
460
|
-
status: 403,
|
|
461
|
-
statusText: "Invalid CSRF Token"
|
|
462
|
-
}
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
handler: csrfHandler
|
|
469
|
-
};
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
// src/plugins/utils.ts
|
|
473
|
-
var getPlugins = (options) => {
|
|
474
|
-
const plugins = {
|
|
475
|
-
post: [],
|
|
476
|
-
pre: [],
|
|
477
|
-
unordered: []
|
|
478
|
-
};
|
|
479
|
-
for (const plugin of options.plugins || []) {
|
|
480
|
-
plugins[plugin.order || "unordered"].push(plugin);
|
|
481
|
-
}
|
|
482
|
-
const internalPlugins = [CSRFCheckPlugin()];
|
|
483
|
-
return [
|
|
484
|
-
...plugins.pre,
|
|
485
|
-
...plugins.unordered,
|
|
486
|
-
...internalPlugins,
|
|
487
|
-
...plugins.post
|
|
488
|
-
];
|
|
489
|
-
};
|
|
490
|
-
var usePlugins = (context, ignorePlugins) => {
|
|
491
|
-
const plugins = context.plugins.filter(
|
|
492
|
-
(pl) => pl.hooks && !ignorePlugins?.includes(pl.id)
|
|
493
|
-
);
|
|
494
|
-
const hooks = plugins.map((plugin) => {
|
|
495
|
-
return plugin.hooks;
|
|
496
|
-
});
|
|
497
|
-
const before = [];
|
|
498
|
-
const after = [];
|
|
499
|
-
for (const hook of hooks) {
|
|
500
|
-
if (hook.matcher(context)) {
|
|
501
|
-
hook.before && before.push(hook.before);
|
|
502
|
-
hook.after && after.push(hook.after);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
return {
|
|
506
|
-
before: async (context2) => {
|
|
507
|
-
let ctx = context2;
|
|
508
|
-
let response;
|
|
509
|
-
for (const hook of before) {
|
|
510
|
-
const res = await hook(ctx);
|
|
511
|
-
if (res?.context) {
|
|
512
|
-
ctx = res.context;
|
|
513
|
-
}
|
|
514
|
-
if (res?.response) {
|
|
515
|
-
response = res.response;
|
|
516
|
-
break;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
return {
|
|
520
|
-
context: ctx,
|
|
521
|
-
response
|
|
522
|
-
};
|
|
523
|
-
},
|
|
524
|
-
after: async (context2, fnResponse) => {
|
|
525
|
-
let ctx = context2;
|
|
526
|
-
let response;
|
|
527
|
-
for (const hook of after) {
|
|
528
|
-
const res = await hook(ctx, fnResponse);
|
|
529
|
-
if (res?.context) {
|
|
530
|
-
ctx = res.context;
|
|
531
|
-
}
|
|
532
|
-
if (res?.response) {
|
|
533
|
-
response = res.response;
|
|
534
|
-
break;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
return {
|
|
538
|
-
context: ctx,
|
|
539
|
-
response
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
};
|
|
543
|
-
};
|
|
544
|
-
var withPlugins = (fn, ignorePlugins) => {
|
|
545
|
-
return async (ctx) => {
|
|
546
|
-
const { before, after } = usePlugins(ctx, ignorePlugins);
|
|
547
|
-
const { context, response } = await before(ctx);
|
|
548
|
-
if (response) {
|
|
549
|
-
return response;
|
|
550
|
-
}
|
|
551
|
-
const res = await fn(context);
|
|
552
|
-
const { response: afterResponse } = await after(context, res);
|
|
553
|
-
if (afterResponse) {
|
|
554
|
-
return afterResponse;
|
|
555
|
-
}
|
|
556
|
-
return res;
|
|
557
|
-
};
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
// ../shared/src/error.ts
|
|
561
|
-
var BetterAuthError = class extends Error {
|
|
562
|
-
constructor(message) {
|
|
563
|
-
super(`${message}`);
|
|
564
|
-
this.name = this.constructor.name;
|
|
565
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
566
|
-
Error.captureStackTrace(this, this.constructor);
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
var MissingSecret = class extends BetterAuthError {
|
|
570
|
-
constructor() {
|
|
571
|
-
super("Missing Secret: A secret is required in a production environment.");
|
|
572
|
-
}
|
|
573
|
-
};
|
|
574
|
-
var InvalidURL = class extends BetterAuthError {
|
|
575
|
-
constructor(message) {
|
|
576
|
-
super(
|
|
577
|
-
message || "Please make sure your config includes valid base URL and base PATH."
|
|
578
|
-
);
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
var InvalidRequest = class extends BetterAuthError {
|
|
582
|
-
constructor() {
|
|
583
|
-
super("Post requests must include a valid JSON parsable body.");
|
|
584
|
-
}
|
|
585
|
-
};
|
|
586
|
-
var ProviderMissing = class extends BetterAuthError {
|
|
587
|
-
constructor(id) {
|
|
588
|
-
super(`Provider ${id} is missing on your configuration.`);
|
|
589
|
-
}
|
|
590
|
-
};
|
|
591
|
-
var ProviderError = class extends BetterAuthError {
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
// src/routes/callback.ts
|
|
595
|
-
import { z as z2 } from "zod";
|
|
596
|
-
|
|
597
|
-
// src/oauth2/signin.ts
|
|
598
|
-
import { base64url } from "jose";
|
|
599
|
-
|
|
600
|
-
// src/crypto/sha.ts
|
|
601
|
-
async function sha256(data) {
|
|
602
|
-
return await crypto.subtle.digest("SHA-256", data);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// src/oauth2/utils.ts
|
|
606
|
-
async function discoveryRequest(context, provider) {
|
|
607
|
-
const issuerIdentifier = new URL(provider.issuer);
|
|
608
|
-
if (!(issuerIdentifier instanceof URL)) {
|
|
609
|
-
throw new TypeError('"issuerIdentifier" must be an instance of URL');
|
|
610
|
-
}
|
|
611
|
-
if (issuerIdentifier.protocol !== "https:" && issuerIdentifier.protocol !== "http:") {
|
|
612
|
-
throw new TypeError('"issuer.protocol" must be "https:" or "http:"');
|
|
613
|
-
}
|
|
614
|
-
const url = new URL(issuerIdentifier.href);
|
|
615
|
-
switch (provider.type) {
|
|
616
|
-
case void 0:
|
|
617
|
-
case "oidc":
|
|
618
|
-
url.pathname = `${url.pathname}/.well-known/openid-configuration`.replace(
|
|
619
|
-
"//",
|
|
620
|
-
"/"
|
|
621
|
-
);
|
|
622
|
-
break;
|
|
623
|
-
case "oauth":
|
|
624
|
-
if (url.pathname === "/") {
|
|
625
|
-
url.pathname = ".well-known/oauth-authorization-server";
|
|
626
|
-
} else {
|
|
627
|
-
url.pathname = `.well-known/oauth-authorization-server/${url.pathname}`.replace(
|
|
628
|
-
"//",
|
|
629
|
-
"/"
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
break;
|
|
633
|
-
default:
|
|
634
|
-
throw new TypeError(`"provider.type" must be "oidc" or "oauth"`);
|
|
635
|
-
}
|
|
636
|
-
const headers = new Headers(context.request.headers);
|
|
637
|
-
headers.set("accept", "application/json");
|
|
638
|
-
return fetch(url.href, {
|
|
639
|
-
headers: Object.fromEntries(headers.entries()),
|
|
640
|
-
method: "GET",
|
|
641
|
-
redirect: "manual"
|
|
642
|
-
}).then((res) => {
|
|
643
|
-
if (!res.ok) {
|
|
644
|
-
throw new Error(`HTTP error! status: ${res.status}`);
|
|
645
|
-
}
|
|
646
|
-
return res.json();
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// src/oauth2/signin.ts
|
|
651
|
-
async function signInOAuth(context, provider, {
|
|
652
|
-
onlySignUp,
|
|
653
|
-
autoCreateSession
|
|
654
|
-
} = {
|
|
655
|
-
autoCreateSession: true,
|
|
656
|
-
onlySignUp: false
|
|
657
|
-
}) {
|
|
658
|
-
if (!provider.params.clientId) {
|
|
659
|
-
throw new ProviderError("clientId is required");
|
|
660
|
-
}
|
|
661
|
-
const scopes = Array.from(new Set(provider?.scopes ?? []));
|
|
662
|
-
const { currentURL, callbackURL, data } = context.request.body;
|
|
663
|
-
const state = generateState(
|
|
664
|
-
currentURL,
|
|
665
|
-
callbackURL,
|
|
666
|
-
data,
|
|
667
|
-
autoCreateSession,
|
|
668
|
-
onlySignUp
|
|
669
|
-
);
|
|
670
|
-
let url = provider.params.authorizationEndpoint;
|
|
671
|
-
if (!url) {
|
|
672
|
-
const discovery = await discoveryRequest(context, provider);
|
|
673
|
-
if (!discovery.authorization_endpoint)
|
|
674
|
-
throw new ProviderError("Missing authorization endpoint");
|
|
675
|
-
url = discovery.authorization_endpoint;
|
|
676
|
-
}
|
|
677
|
-
const authorizationUrl = new URL(url);
|
|
678
|
-
authorizationUrl.searchParams.set("response_type", "code");
|
|
679
|
-
authorizationUrl.searchParams.set("client_id", provider.params.clientId);
|
|
680
|
-
authorizationUrl.searchParams.set("state", state);
|
|
681
|
-
authorizationUrl.searchParams.set("scope", scopes.join(" "));
|
|
682
|
-
authorizationUrl.searchParams.set(
|
|
683
|
-
"redirect_uri",
|
|
684
|
-
provider.params.redirectURL || `${context.request.url.toString()}/callback/${context.request.body.provider}`
|
|
685
|
-
);
|
|
686
|
-
if (provider.type === "oidc") {
|
|
687
|
-
if (provider.nonce) {
|
|
688
|
-
const nonce = generateRandomString(24);
|
|
689
|
-
authorizationUrl.searchParams.set("nonce", nonce);
|
|
690
|
-
context.request.cookies.set(
|
|
691
|
-
context.cookies.nonce.name,
|
|
692
|
-
nonce,
|
|
693
|
-
context.cookies.nonce.options
|
|
694
|
-
);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
provider.params.responseMode && authorizationUrl.searchParams.set(
|
|
698
|
-
"response_mode",
|
|
699
|
-
provider.params.responseMode
|
|
700
|
-
);
|
|
701
|
-
if (provider.params.extra) {
|
|
702
|
-
const extra = Object.entries(provider.params.extra);
|
|
703
|
-
for (const [key, value] of extra) {
|
|
704
|
-
authorizationUrl.searchParams.set(key, value);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
const codeVerifier = provider.pkCodeVerifier ? generateCodeVerifier() : void 0;
|
|
708
|
-
if (provider.pkCodeVerifier && codeVerifier) {
|
|
709
|
-
const codeChallengeMethod = provider?.codeChallengeMethod ?? "S256";
|
|
710
|
-
if (codeChallengeMethod === "S256") {
|
|
711
|
-
const codeChallengeBuffer = await sha256(
|
|
712
|
-
new TextEncoder().encode(codeVerifier)
|
|
713
|
-
);
|
|
714
|
-
const codeChallenge = base64url.encode(
|
|
715
|
-
new Uint8Array(codeChallengeBuffer)
|
|
716
|
-
);
|
|
717
|
-
authorizationUrl.searchParams.set("code_challenge", codeChallenge);
|
|
718
|
-
authorizationUrl.searchParams.set("code_challenge_method", "S256");
|
|
719
|
-
} else {
|
|
720
|
-
authorizationUrl.searchParams.set("code_challenge", codeVerifier);
|
|
721
|
-
authorizationUrl.searchParams.set("code_challenge_method", "plain");
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
context.request.cookies.set(
|
|
725
|
-
context.cookies.state.name,
|
|
726
|
-
state,
|
|
727
|
-
context.cookies.state.options
|
|
728
|
-
);
|
|
729
|
-
if (codeVerifier) {
|
|
730
|
-
context.request.cookies.set(
|
|
731
|
-
context.cookies.pkCodeVerifier.name,
|
|
732
|
-
codeVerifier,
|
|
733
|
-
context.cookies.pkCodeVerifier.options
|
|
734
|
-
);
|
|
735
|
-
}
|
|
736
|
-
return authorizationUrl.toString();
|
|
737
|
-
}
|
|
738
|
-
function generateCodeVerifier() {
|
|
739
|
-
const randomValues = new Uint8Array(32);
|
|
740
|
-
crypto.getRandomValues(randomValues);
|
|
741
|
-
return base64url.encode(randomValues);
|
|
742
|
-
}
|
|
743
|
-
function generateState(currentURL, callbackURL, signUp2, autoCreateSession, onlySignUp) {
|
|
744
|
-
let state = generateRandomString(24);
|
|
745
|
-
state += `!${currentURL}`;
|
|
746
|
-
state += `!${callbackURL || currentURL}`;
|
|
747
|
-
state += `!${JSON.stringify({
|
|
748
|
-
data: signUp2,
|
|
749
|
-
autoCreateSession,
|
|
750
|
-
onlySignUp
|
|
751
|
-
})}`;
|
|
752
|
-
return state;
|
|
753
|
-
}
|
|
754
|
-
function getState(state) {
|
|
755
|
-
const [hash, currentURL, callbackURL, signUpString] = state.split("!");
|
|
756
|
-
if (!hash || !currentURL || !callbackURL) {
|
|
757
|
-
throw new ProviderError("Invalid state");
|
|
758
|
-
}
|
|
759
|
-
const signUp2 = signUpString ? JSON.parse(signUpString) : void 0;
|
|
760
|
-
return {
|
|
761
|
-
hash,
|
|
762
|
-
currentURL,
|
|
763
|
-
callbackURL,
|
|
764
|
-
signUp: {
|
|
765
|
-
data: signUp2?.data,
|
|
766
|
-
autoCreateSession: signUp2?.autoCreateSession,
|
|
767
|
-
onlySignUp: signUp2?.onlySignUp
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// src/oauth2/tokens.ts
|
|
773
|
-
import { base64url as base64url2 } from "jose";
|
|
774
|
-
async function getTokens(context, provider) {
|
|
775
|
-
const redirectURL = provider.params.redirectURL || `${context.baseURL}${context.basePath}/callback/${provider.id}`;
|
|
776
|
-
const headers = new Headers();
|
|
777
|
-
headers.set("Content-Type", "application/x-www-form-urlencoded");
|
|
778
|
-
headers.set("Accept", "application/json");
|
|
779
|
-
headers.set("User-Agent", "better-auth");
|
|
780
|
-
const encodedCredentials = base64url2.encode(
|
|
781
|
-
`${provider.params.clientId}:${provider.params.clientSecret}`
|
|
782
|
-
);
|
|
783
|
-
headers.set("Authorization", `Basic ${encodedCredentials}`);
|
|
784
|
-
const body = new URLSearchParams();
|
|
785
|
-
body.set("grant_type", "authorization_code");
|
|
786
|
-
body.set("code", context.request.query.code);
|
|
787
|
-
body.set("redirect_uri", redirectURL);
|
|
788
|
-
if (provider.pkCodeVerifier) {
|
|
789
|
-
const codeVerifier = context.request.cookies.get(
|
|
790
|
-
context.cookies.pkCodeVerifier.name
|
|
791
|
-
);
|
|
792
|
-
codeVerifier && body.set("code_verifier", codeVerifier);
|
|
793
|
-
}
|
|
794
|
-
body.set("client_id", provider.params.clientId);
|
|
795
|
-
body.set("client_secret", provider.params.clientSecret);
|
|
796
|
-
let url = provider.params.tokenEndpoint;
|
|
797
|
-
if (!url) {
|
|
798
|
-
const discovery = await discoveryRequest(context, provider);
|
|
799
|
-
if (!discovery.token_endpoint) {
|
|
800
|
-
throw new Error("Missing token endpoint");
|
|
801
|
-
}
|
|
802
|
-
url = discovery.token_endpoint;
|
|
803
|
-
}
|
|
804
|
-
const response = await fetch(url, {
|
|
805
|
-
method: "POST",
|
|
806
|
-
body,
|
|
807
|
-
headers
|
|
808
|
-
});
|
|
809
|
-
const data = await response.json();
|
|
810
|
-
return data;
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
// src/providers/utils.ts
|
|
814
|
-
var getProvider = (context, providerId) => {
|
|
815
|
-
const providers = context.providers;
|
|
816
|
-
const provider = providers.find((provider2) => provider2.id === providerId);
|
|
817
|
-
return provider;
|
|
818
|
-
};
|
|
819
|
-
|
|
820
|
-
// src/routes/callback.ts
|
|
821
|
-
var callbackQuerySchema = z2.object({
|
|
822
|
-
code: z2.string(),
|
|
823
|
-
state: z2.string(),
|
|
824
|
-
provider: z2.string()
|
|
825
|
-
});
|
|
826
|
-
var callback = async (context) => {
|
|
827
|
-
const parsedQuery = callbackQuerySchema.safeParse(context.request.query);
|
|
828
|
-
if (!parsedQuery.success) {
|
|
829
|
-
const error = context.request.url.searchParams.get("error");
|
|
830
|
-
const errorDesc = context.request.url.searchParams.get("error_description");
|
|
831
|
-
const state = context.request.url.searchParams.get("state");
|
|
832
|
-
if (!state) {
|
|
833
|
-
throw new ProviderError(
|
|
834
|
-
`state is not returned from ${context.request.url.searchParams.get(
|
|
835
|
-
"provider"
|
|
836
|
-
)}`
|
|
837
|
-
);
|
|
838
|
-
}
|
|
839
|
-
const { currentURL } = getState(state);
|
|
840
|
-
return {
|
|
841
|
-
status: 302,
|
|
842
|
-
headers: {
|
|
843
|
-
Location: `${currentURL}?error=${error}&error_description=${errorDesc}`
|
|
844
|
-
}
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
const provider = getProvider(context, parsedQuery.data.provider);
|
|
848
|
-
if (provider?.type === "oauth" || provider?.type === "oidc") {
|
|
849
|
-
const storedState = context.request.cookies.get(context.cookies.state.name);
|
|
850
|
-
const state = parsedQuery.data.state;
|
|
851
|
-
const { currentURL } = getState(state);
|
|
852
|
-
if (storedState !== state) {
|
|
853
|
-
return {
|
|
854
|
-
status: 302,
|
|
855
|
-
headers: {
|
|
856
|
-
Location: `${currentURL}?error=invalid_state`
|
|
857
|
-
}
|
|
858
|
-
};
|
|
859
|
-
}
|
|
860
|
-
const tokens = await getTokens(context, provider);
|
|
861
|
-
if (tokens.error) {
|
|
862
|
-
return {
|
|
863
|
-
status: 302,
|
|
864
|
-
headers: {
|
|
865
|
-
Location: `${currentURL}?error=${tokens.error}`
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
|
-
}
|
|
869
|
-
if (provider.type === "oauth" || provider.type === "oidc") {
|
|
870
|
-
const profile = await provider.getUserInfo(tokens);
|
|
871
|
-
const {
|
|
872
|
-
callbackURL,
|
|
873
|
-
currentURL: currentURL2,
|
|
874
|
-
signUp: { data, autoCreateSession, onlySignUp }
|
|
875
|
-
} = getState(state);
|
|
876
|
-
let userAccount = await context.adapter.findAccount(
|
|
877
|
-
{
|
|
878
|
-
providerId: provider.id,
|
|
879
|
-
accountId: profile.id
|
|
880
|
-
},
|
|
881
|
-
context
|
|
882
|
-
);
|
|
883
|
-
if (provider.type === "oidc") {
|
|
884
|
-
if (profile.nonce) {
|
|
885
|
-
const nonce = context.request.cookies.get(context.cookies.nonce.name);
|
|
886
|
-
if (profile.nonce !== nonce) {
|
|
887
|
-
return {
|
|
888
|
-
status: 302,
|
|
889
|
-
headers: {
|
|
890
|
-
Location: `${currentURL2}?error=invalid_nonce`
|
|
891
|
-
}
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
if (onlySignUp && userAccount) {
|
|
897
|
-
return {
|
|
898
|
-
status: 302,
|
|
899
|
-
headers: {
|
|
900
|
-
Location: `${currentURL2}?error=user_already_exist`
|
|
901
|
-
}
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
let userData = null;
|
|
905
|
-
if (!userAccount) {
|
|
906
|
-
if (provider.params.linkAccounts) {
|
|
907
|
-
const shouldLink = provider.params.linkAccounts.enabler ? await provider.params.linkAccounts.enabler(profile) : true;
|
|
908
|
-
if (shouldLink) {
|
|
909
|
-
const { field, key } = provider.params.linkAccounts;
|
|
910
|
-
const user = await context._db.findOne({
|
|
911
|
-
model: context.user.modelName,
|
|
912
|
-
where: [
|
|
913
|
-
{
|
|
914
|
-
field,
|
|
915
|
-
value: profile[key]
|
|
916
|
-
}
|
|
917
|
-
]
|
|
918
|
-
});
|
|
919
|
-
if (user) {
|
|
920
|
-
userAccount = await context.adapter.linkAccount(
|
|
921
|
-
{
|
|
922
|
-
userId: user.id,
|
|
923
|
-
providerId: provider.id,
|
|
924
|
-
accountId: profile.id
|
|
925
|
-
},
|
|
926
|
-
context
|
|
927
|
-
);
|
|
928
|
-
userData = user;
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
if (!userData && !data) {
|
|
933
|
-
return {
|
|
934
|
-
status: 302,
|
|
935
|
-
headers: {
|
|
936
|
-
Location: `${callbackURL}?error=user_not_found`
|
|
937
|
-
}
|
|
938
|
-
};
|
|
939
|
-
}
|
|
940
|
-
if (!userData) {
|
|
941
|
-
let signUpData = {};
|
|
942
|
-
for (const key in data) {
|
|
943
|
-
if (typeof data[key] === "string") {
|
|
944
|
-
const constructedKey = data[key].split(".");
|
|
945
|
-
let value = profile;
|
|
946
|
-
for (const k of constructedKey) {
|
|
947
|
-
value = value[k];
|
|
948
|
-
}
|
|
949
|
-
signUpData[key] = value;
|
|
950
|
-
} else if ("value" in data[key]) {
|
|
951
|
-
signUpData[key] = data[key].value;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
signUpData = parseUser(signUpData, context);
|
|
955
|
-
const accountData = {
|
|
956
|
-
providerId: provider.id,
|
|
957
|
-
accountId: profile.id
|
|
958
|
-
};
|
|
959
|
-
for (const key in context.account.additionalFields) {
|
|
960
|
-
accountData[key] = tokens[context.account.additionalFields[key]];
|
|
961
|
-
}
|
|
962
|
-
try {
|
|
963
|
-
const { user, account } = await context.adapter.createUser(
|
|
964
|
-
{
|
|
965
|
-
user: signUpData,
|
|
966
|
-
account: accountData
|
|
967
|
-
},
|
|
968
|
-
context
|
|
969
|
-
);
|
|
970
|
-
userAccount = account;
|
|
971
|
-
userData = user;
|
|
972
|
-
} catch (e) {
|
|
973
|
-
return {
|
|
974
|
-
status: 302,
|
|
975
|
-
headers: {
|
|
976
|
-
Location: `${currentURL2}?error=user_already_exist`
|
|
977
|
-
}
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
if (!userData) {
|
|
983
|
-
userData = await context.adapter.findUserById(
|
|
984
|
-
userAccount?.userId,
|
|
985
|
-
context
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
if (autoCreateSession) {
|
|
989
|
-
const session2 = await context.adapter.createSession(
|
|
990
|
-
userData?.id,
|
|
991
|
-
context
|
|
992
|
-
);
|
|
993
|
-
setSessionCookie(context, session2.id);
|
|
994
|
-
}
|
|
995
|
-
return {
|
|
996
|
-
status: 302,
|
|
997
|
-
headers: {
|
|
998
|
-
Location: callbackURL
|
|
999
|
-
}
|
|
1000
|
-
};
|
|
1001
|
-
}
|
|
1002
|
-
return {
|
|
1003
|
-
status: 200
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
throw new ProviderError("Invalid provider type");
|
|
1007
|
-
};
|
|
1008
|
-
var callbackHandler = withPlugins(callback, ["csrf"]);
|
|
1009
|
-
|
|
1010
|
-
// src/routes/session.ts
|
|
1011
|
-
var session = async (context) => {
|
|
1012
|
-
const session2 = await getServerSession(context);
|
|
1013
|
-
if (!session2) {
|
|
1014
|
-
return {
|
|
1015
|
-
status: 401,
|
|
1016
|
-
statusText: "Unauthorize"
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
|
-
return {
|
|
1020
|
-
status: 200,
|
|
1021
|
-
body: session2
|
|
1022
|
-
};
|
|
1023
|
-
};
|
|
1024
|
-
var getServerSession = async (context) => {
|
|
1025
|
-
const sessionFromCookie = context.request.cookies.get(
|
|
1026
|
-
context.cookies.sessionToken.name
|
|
1027
|
-
);
|
|
1028
|
-
if (!sessionFromCookie) {
|
|
1029
|
-
return null;
|
|
1030
|
-
}
|
|
1031
|
-
const session2 = await context.adapter.findSession(sessionFromCookie, context);
|
|
1032
|
-
if (!session2 || session2.expiresAt < /* @__PURE__ */ new Date()) {
|
|
1033
|
-
session2 && await context.adapter.deleteSession(session2.id, context);
|
|
1034
|
-
deleteSessionCooke(context);
|
|
1035
|
-
return null;
|
|
1036
|
-
}
|
|
1037
|
-
const user = await context.adapter.findUserById(session2.userId, context);
|
|
1038
|
-
if (!user) {
|
|
1039
|
-
return null;
|
|
1040
|
-
}
|
|
1041
|
-
const updatedSession = await context.adapter.updateSession(session2, context);
|
|
1042
|
-
context.request.cookies.set(context.cookies.sessionToken.name, session2.id, {
|
|
1043
|
-
...context.cookies.sessionToken.options,
|
|
1044
|
-
maxAge: updatedSession.expiresAt.valueOf() - Date.now()
|
|
1045
|
-
});
|
|
1046
|
-
sessionFromCookie;
|
|
1047
|
-
return {
|
|
1048
|
-
user,
|
|
1049
|
-
expiresAt: session2.expiresAt
|
|
1050
|
-
};
|
|
1051
|
-
};
|
|
1052
|
-
var sessionHandler = withPlugins(session);
|
|
1053
|
-
|
|
1054
|
-
// src/routes/signin.ts
|
|
1055
|
-
import { z as z3 } from "zod";
|
|
1056
|
-
var bodySchema = z3.object({
|
|
1057
|
-
provider: z3.string(),
|
|
1058
|
-
data: z3.record(z3.string(), z3.any()).optional(),
|
|
1059
|
-
callbackURL: z3.string().optional(),
|
|
1060
|
-
currentURL: z3.string()
|
|
1061
|
-
});
|
|
1062
|
-
var signIn = async (context) => {
|
|
1063
|
-
const data = bodySchema.parse(context.request.body);
|
|
1064
|
-
const provider = getProvider(context, data.provider);
|
|
1065
|
-
if (!provider) {
|
|
1066
|
-
throw new ProviderMissing(data.provider);
|
|
1067
|
-
}
|
|
1068
|
-
if (provider.type === "oauth" || provider.type === "oidc") {
|
|
1069
|
-
const url = await signInOAuth(context, provider);
|
|
1070
|
-
return {
|
|
1071
|
-
status: 200,
|
|
1072
|
-
body: {
|
|
1073
|
-
url,
|
|
1074
|
-
redirect: true
|
|
1075
|
-
}
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
if (provider.type === "custom") {
|
|
1079
|
-
if (!provider.signIn) {
|
|
1080
|
-
throw new ProviderError("Sign in method not implemented");
|
|
1081
|
-
}
|
|
1082
|
-
const response = await provider.signIn(context);
|
|
1083
|
-
return response;
|
|
1084
|
-
}
|
|
1085
|
-
throw new ProviderError("Invalid provider type");
|
|
1086
|
-
};
|
|
1087
|
-
var signInHandler = withPlugins(signIn);
|
|
1088
|
-
|
|
1089
|
-
// src/routes/signout.ts
|
|
1090
|
-
var signOut = async (context) => {
|
|
1091
|
-
const session2 = context.request.cookies.get(
|
|
1092
|
-
context.cookies.sessionToken.name
|
|
1093
|
-
);
|
|
1094
|
-
deleteSessionCooke(context);
|
|
1095
|
-
if (session2) {
|
|
1096
|
-
try {
|
|
1097
|
-
await context.adapter.deleteSession(session2, context);
|
|
1098
|
-
} catch (e) {
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
return {
|
|
1102
|
-
status: 200
|
|
1103
|
-
};
|
|
1104
|
-
};
|
|
1105
|
-
var signOutHandler = withPlugins(signOut);
|
|
1106
|
-
|
|
1107
|
-
// src/routes/signup.ts
|
|
1108
|
-
import { z as z4 } from "zod";
|
|
1109
|
-
var signUpSchema = z4.object({
|
|
1110
|
-
data: z4.record(z4.string(), z4.any()).optional(),
|
|
1111
|
-
provider: z4.string(),
|
|
1112
|
-
currentURL: z4.string(),
|
|
1113
|
-
callbackURL: z4.string().optional(),
|
|
1114
|
-
autoCreateSession: z4.boolean().optional()
|
|
1115
|
-
});
|
|
1116
|
-
var signUp = async (context) => {
|
|
1117
|
-
const data = signUpSchema.parse(context.request.body);
|
|
1118
|
-
const provider = getProvider(context, data.provider);
|
|
1119
|
-
if (!provider) {
|
|
1120
|
-
throw new ProviderMissing(data.provider);
|
|
1121
|
-
}
|
|
1122
|
-
if (provider?.type === "oauth" || provider?.type === "oidc") {
|
|
1123
|
-
context.request.body.signUp = context.request.body.data;
|
|
1124
|
-
const url = await signInOAuth(context, provider, {
|
|
1125
|
-
autoCreateSession: data.autoCreateSession ?? true,
|
|
1126
|
-
onlySignUp: true
|
|
1127
|
-
});
|
|
1128
|
-
return {
|
|
1129
|
-
status: 200,
|
|
1130
|
-
body: {
|
|
1131
|
-
url,
|
|
1132
|
-
redirect: true
|
|
1133
|
-
}
|
|
1134
|
-
};
|
|
1135
|
-
}
|
|
1136
|
-
if (!provider.signUp) {
|
|
1137
|
-
throw new ProviderError("Sign up method not implemented");
|
|
1138
|
-
}
|
|
1139
|
-
return await provider.signUp(context);
|
|
1140
|
-
};
|
|
1141
|
-
var signUpHandler = withPlugins(signUp);
|
|
1142
|
-
|
|
1143
|
-
// src/utils/request.ts
|
|
1144
|
-
import { IncomingMessage } from "http";
|
|
1145
|
-
import { z as z5 } from "zod";
|
|
1146
|
-
async function getBody(request) {
|
|
1147
|
-
try {
|
|
1148
|
-
if (request instanceof Request)
|
|
1149
|
-
return await request.json();
|
|
1150
|
-
return new Promise((resolve) => {
|
|
1151
|
-
const bodyParts = [];
|
|
1152
|
-
let body;
|
|
1153
|
-
request.on("data", (chunk) => {
|
|
1154
|
-
bodyParts.push(chunk);
|
|
1155
|
-
}).on("end", () => {
|
|
1156
|
-
body = Buffer.concat(bodyParts).toString();
|
|
1157
|
-
resolve(JSON.parse(body));
|
|
1158
|
-
});
|
|
1159
|
-
});
|
|
1160
|
-
} catch {
|
|
1161
|
-
throw new InvalidRequest();
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
var toRequestHeader = (incomingHeaders) => {
|
|
1165
|
-
if (incomingHeaders instanceof Headers)
|
|
1166
|
-
return incomingHeaders;
|
|
1167
|
-
const headers = new Headers();
|
|
1168
|
-
for (const [key, value] of Object.entries(incomingHeaders)) {
|
|
1169
|
-
if (Array.isArray(value)) {
|
|
1170
|
-
for (const val of value) {
|
|
1171
|
-
headers.append(key, val);
|
|
1172
|
-
}
|
|
1173
|
-
} else if (value) {
|
|
1174
|
-
headers.append(key, value);
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
return headers;
|
|
1178
|
-
};
|
|
1179
|
-
function parseUrl(request, options) {
|
|
1180
|
-
let requestStringURL = request instanceof IncomingMessage ? `${request.headers.host}${request.url}` : request.url;
|
|
1181
|
-
if (!requestStringURL.startsWith("http")) {
|
|
1182
|
-
if (requestStringURL.startsWith("localhost")) {
|
|
1183
|
-
requestStringURL = `http://${requestStringURL}`;
|
|
1184
|
-
} else {
|
|
1185
|
-
requestStringURL = `https://${requestStringURL}`;
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
const requestURL = new URL(requestStringURL);
|
|
1189
|
-
const baseURL = requestURL.origin;
|
|
1190
|
-
const basePath = options.basePath || "/api/auth";
|
|
1191
|
-
let urlString = `${baseURL}${basePath}`;
|
|
1192
|
-
if (!urlString.startsWith("http")) {
|
|
1193
|
-
urlString = `https://${urlString}`;
|
|
1194
|
-
}
|
|
1195
|
-
const isValidURL = z5.string().url().safeParse(urlString);
|
|
1196
|
-
let action = requestURL.pathname.split(basePath)[1] || "";
|
|
1197
|
-
action = action.replace("/", "");
|
|
1198
|
-
if (isValidURL.error) {
|
|
1199
|
-
throw new InvalidURL();
|
|
1200
|
-
}
|
|
1201
|
-
if (action.startsWith("callback")) {
|
|
1202
|
-
const provider = action.split("/")[1];
|
|
1203
|
-
if (!provider)
|
|
1204
|
-
throw new InvalidURL("Provider is missing in the URL.");
|
|
1205
|
-
action = "callback";
|
|
1206
|
-
requestURL.searchParams.set("provider", provider);
|
|
1207
|
-
}
|
|
1208
|
-
const url = new URL(urlString);
|
|
1209
|
-
requestURL.searchParams.forEach((value, key) => {
|
|
1210
|
-
url.searchParams.set(key, value);
|
|
1211
|
-
});
|
|
1212
|
-
return {
|
|
1213
|
-
url,
|
|
1214
|
-
action
|
|
1215
|
-
};
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
// src/utils/secret.ts
|
|
1219
|
-
var DEFAULT_SECRET = "better-auth-secret-key-123456789";
|
|
1220
|
-
var getSecret = (secret) => {
|
|
1221
|
-
secret = secret || process.env.BETTER_AUTH_SECRET || process.env.AUTH_SECRET;
|
|
1222
|
-
if (process.env.NODE_ENV === "production" && !secret) {
|
|
1223
|
-
throw new MissingSecret();
|
|
1224
|
-
}
|
|
1225
|
-
return secret || DEFAULT_SECRET;
|
|
1226
|
-
};
|
|
1227
|
-
|
|
1228
|
-
// src/auth.ts
|
|
1229
|
-
var toContext = async (options, request, handlerOptions) => {
|
|
1230
|
-
const basePath = options.basePath || "/api/auth";
|
|
1231
|
-
const headers = toRequestHeader(request.headers);
|
|
1232
|
-
const { url, action } = parseUrl(request, options);
|
|
1233
|
-
const body = request.method?.toUpperCase() === "POST" ? await getBody(request) : null;
|
|
1234
|
-
return {
|
|
1235
|
-
baseURL: url.origin,
|
|
1236
|
-
basePath,
|
|
1237
|
-
request: {
|
|
1238
|
-
method: request.method,
|
|
1239
|
-
url,
|
|
1240
|
-
query: Object.fromEntries(url.searchParams),
|
|
1241
|
-
action,
|
|
1242
|
-
body,
|
|
1243
|
-
headers,
|
|
1244
|
-
cookies: handlerOptions?.cookieManager || cookieManager(headers)
|
|
1245
|
-
},
|
|
1246
|
-
_db: options.adapter,
|
|
1247
|
-
providers: options.providers,
|
|
1248
|
-
secret: getSecret(options.secret),
|
|
1249
|
-
adapter: createInternalAdapter(options.adapter),
|
|
1250
|
-
plugins: getPlugins(options),
|
|
1251
|
-
cookies: getCookies(options),
|
|
1252
|
-
disableCSRF: options.advanced?.skipCSRFCheck || false,
|
|
1253
|
-
session: {
|
|
1254
|
-
modelName: options.session?.modelName || "session",
|
|
1255
|
-
updateAge: options.session?.updateAge === void 0 ? timeSpan("1d") : options.session.updateAge,
|
|
1256
|
-
expiresIn: options.session?.expiresIn || timeSpan("1w"),
|
|
1257
|
-
additionalFields: options.session?.additionalFields ? toInternalFields(options.session.additionalFields) : {},
|
|
1258
|
-
selectFields: getSelectFields(
|
|
1259
|
-
options.session?.additionalFields || {},
|
|
1260
|
-
"session"
|
|
1261
|
-
)
|
|
1262
|
-
},
|
|
1263
|
-
user: {
|
|
1264
|
-
modelName: options.user?.modelName || "user",
|
|
1265
|
-
fields: options.user?.fields ? toInternalFields(options.user.fields) : {},
|
|
1266
|
-
selectFields: getSelectFields(options.user?.fields || {}, "user")
|
|
1267
|
-
},
|
|
1268
|
-
account: {
|
|
1269
|
-
modelName: options.account?.modelName || "account",
|
|
1270
|
-
additionalFields: options.account?.additionalFields || {},
|
|
1271
|
-
selectFields: [
|
|
1272
|
-
...Object.keys(options.account?.additionalFields || {}),
|
|
1273
|
-
"userId",
|
|
1274
|
-
"providerId",
|
|
1275
|
-
"accountId"
|
|
1276
|
-
]
|
|
1277
|
-
},
|
|
1278
|
-
sessionAdapter: options.sessionAdapter
|
|
1279
|
-
};
|
|
1280
|
-
};
|
|
1281
|
-
var toResponse = (res, context, handlerOptions) => {
|
|
1282
|
-
if (handlerOptions?.toResponse) {
|
|
1283
|
-
return handlerOptions.toResponse(res, context);
|
|
1284
|
-
}
|
|
1285
|
-
context.request.headers.set("content-type", "application/json");
|
|
1286
|
-
const response = new Response(res.body ? JSON.stringify(res.body) : null, {
|
|
1287
|
-
headers: {
|
|
1288
|
-
...context.request.headers,
|
|
1289
|
-
"Set-Cookie": context.request.headers.get("Set-Cookie") ?? "",
|
|
1290
|
-
...res.headers
|
|
1291
|
-
},
|
|
1292
|
-
status: res.status,
|
|
1293
|
-
statusText: res.statusText
|
|
1294
|
-
});
|
|
1295
|
-
return response;
|
|
1296
|
-
};
|
|
1297
|
-
|
|
1298
|
-
// src/actions/index.ts
|
|
1299
|
-
function getActions(options, handlerOptions) {
|
|
1300
|
-
const actions = {
|
|
1301
|
-
/**
|
|
1302
|
-
* Sign in with a provider. This action will return response object. If
|
|
1303
|
-
* it's oauth, it will redirect to the provider. If it's custom, it
|
|
1304
|
-
* will return the response object and it'll set the cookies.
|
|
1305
|
-
*
|
|
1306
|
-
* ► In most cases you should just be using
|
|
1307
|
-
* client sdk for sign in instead unless you
|
|
1308
|
-
* have a good reason to use this.
|
|
1309
|
-
*/
|
|
1310
|
-
signIn: async (request, input) => {
|
|
1311
|
-
const url = request instanceof Headers ? request.get("referer") : request.url;
|
|
1312
|
-
const req = new Request(url, {
|
|
1313
|
-
body: JSON.stringify(input),
|
|
1314
|
-
method: "POST"
|
|
1315
|
-
});
|
|
1316
|
-
const context = await toContext(options, req);
|
|
1317
|
-
context.disableCSRF = true;
|
|
1318
|
-
context.request.body = {
|
|
1319
|
-
currentURL: url,
|
|
1320
|
-
provider: input.provider
|
|
1321
|
-
};
|
|
1322
|
-
const response = await signInHandler(context);
|
|
1323
|
-
if (response.body.redirect) {
|
|
1324
|
-
return toResponse(
|
|
1325
|
-
{
|
|
1326
|
-
status: 302,
|
|
1327
|
-
headers: {
|
|
1328
|
-
Location: response.body.url
|
|
1329
|
-
}
|
|
1330
|
-
},
|
|
1331
|
-
context
|
|
1332
|
-
);
|
|
1333
|
-
}
|
|
1334
|
-
return toResponse(response, context, handlerOptions);
|
|
1335
|
-
},
|
|
1336
|
-
/**
|
|
1337
|
-
* Get the current logged in user session.
|
|
1338
|
-
*/
|
|
1339
|
-
getSession: async (request) => {
|
|
1340
|
-
const url = request instanceof Headers ? request.get("referer") || request.get("x-forwarded-host") || "http://localhost" : request.url;
|
|
1341
|
-
const req = request instanceof Request ? request : new Request(url, {
|
|
1342
|
-
method: "POST",
|
|
1343
|
-
body: JSON.stringify({}),
|
|
1344
|
-
headers: request
|
|
1345
|
-
});
|
|
1346
|
-
const context = await toContext(options, req);
|
|
1347
|
-
context.disableCSRF = true;
|
|
1348
|
-
const response = await getServerSession(context);
|
|
1349
|
-
return response;
|
|
1350
|
-
},
|
|
1351
|
-
/**
|
|
1352
|
-
* Signout the current user.
|
|
1353
|
-
* Delete the session and clear the cookies.
|
|
1354
|
-
*/
|
|
1355
|
-
signOut: async (request) => {
|
|
1356
|
-
const url = request instanceof Headers ? request.get("referer") : request.url;
|
|
1357
|
-
const req = request instanceof Request ? request : new Request(url, {
|
|
1358
|
-
method: "POST",
|
|
1359
|
-
body: JSON.stringify({}),
|
|
1360
|
-
headers: request
|
|
1361
|
-
});
|
|
1362
|
-
const context = await toContext(options, req);
|
|
1363
|
-
context.disableCSRF = true;
|
|
1364
|
-
const response = await signOutHandler(context);
|
|
1365
|
-
return toResponse(response, context, handlerOptions);
|
|
1366
|
-
}
|
|
1367
|
-
};
|
|
1368
|
-
return actions;
|
|
1369
|
-
}
|
|
1370
|
-
export {
|
|
1371
|
-
getActions
|
|
1372
|
-
};
|
|
1373
|
-
//# sourceMappingURL=actions.js.map
|