@mastra/auth-better-auth 1.1.2-alpha.0 → 1.1.2-alpha.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/CHANGELOG.md +38 -0
- package/dist/_types/@internal_auth/dist/ee/fga-check.d.ts +2 -5
- package/dist/_types/@internal_auth/dist/ee/interfaces/fga.d.ts +47 -0
- package/dist/_types/@internal_auth/dist/index.d.ts +66 -0
- package/dist/_types/@internal_auth/dist/provider/index.d.ts +8 -1
- package/dist/index.cjs +329 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +92 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +329 -31
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { LibsqlDialect } from '@libsql/kysely-libsql';
|
|
2
|
+
import { betterAuth } from 'better-auth';
|
|
3
|
+
import { makeSignature } from 'better-auth/crypto';
|
|
4
|
+
import { getMigrations } from 'better-auth/db/migration';
|
|
5
|
+
import { organization } from 'better-auth/plugins';
|
|
6
|
+
|
|
1
7
|
// ../../packages/_internal-core/dist/chunk-3M4SEWMI.js
|
|
2
8
|
var RegisteredLogger = {
|
|
3
9
|
LLM: "LLM"};
|
|
@@ -150,7 +156,7 @@ var MastraBase = class {
|
|
|
150
156
|
}
|
|
151
157
|
};
|
|
152
158
|
|
|
153
|
-
// ../../packages/_internals/auth/dist/chunk-
|
|
159
|
+
// ../../packages/_internals/auth/dist/chunk-NJOKT6V5.js
|
|
154
160
|
var MastraAuthProvider = class extends MastraBase {
|
|
155
161
|
protected;
|
|
156
162
|
public;
|
|
@@ -178,8 +184,13 @@ var MastraAuthProvider = class extends MastraBase {
|
|
|
178
184
|
}
|
|
179
185
|
}
|
|
180
186
|
};
|
|
181
|
-
|
|
182
|
-
|
|
187
|
+
function tryDecode(value) {
|
|
188
|
+
try {
|
|
189
|
+
return decodeURIComponent(value);
|
|
190
|
+
} catch {
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
183
194
|
function getRequestHeader2(request, name) {
|
|
184
195
|
if (request instanceof Request) {
|
|
185
196
|
return request.headers.get(name);
|
|
@@ -200,23 +211,253 @@ function mapBetterAuthUserToEEUser(user) {
|
|
|
200
211
|
};
|
|
201
212
|
}
|
|
202
213
|
var MastraAuthBetterAuth = class extends MastraAuthProvider {
|
|
203
|
-
auth;
|
|
214
|
+
#auth;
|
|
215
|
+
#secret;
|
|
216
|
+
/** True when `init()` built the instance — then we also own its migrations. */
|
|
217
|
+
#ownsInstance = false;
|
|
218
|
+
/** Once-per-process migration latch; reset on failure so a later call retries. */
|
|
219
|
+
#migrated;
|
|
220
|
+
/** In-process `userId → orgId` cache so hosts can call `ensureOrganization` per request. */
|
|
221
|
+
#orgCache = /* @__PURE__ */ new Map();
|
|
222
|
+
/** Set from `init()`: cross-origin SPA deploys need SameSite=None; Secure cookies. */
|
|
223
|
+
#crossSite = false;
|
|
204
224
|
signUpEnabledConfig;
|
|
205
|
-
sessionCookieName;
|
|
206
225
|
constructor(options) {
|
|
207
226
|
super({ name: options?.name ?? "better-auth" });
|
|
208
|
-
if (!options.auth) {
|
|
227
|
+
if (!options.auth && !options.secret) {
|
|
209
228
|
throw new Error(
|
|
210
|
-
"Better Auth instance is required. Please provide the auth option with your Better Auth instance created via betterAuth({ ... })"
|
|
229
|
+
"Better Auth instance is required. Please provide the auth option with your Better Auth instance created via betterAuth({ ... }), or provide `secret` so the provider can build its own instance in init() on the host database."
|
|
211
230
|
);
|
|
212
231
|
}
|
|
213
|
-
this
|
|
232
|
+
this.#auth = options.auth;
|
|
233
|
+
this.#secret = options.secret;
|
|
214
234
|
this.signUpEnabledConfig = options.signUpEnabled ?? true;
|
|
215
|
-
const authWithOptions = this.auth;
|
|
216
|
-
const prefix = authWithOptions.options?.advanced?.cookiePrefix ?? "better-auth";
|
|
217
|
-
this.sessionCookieName = `${prefix}.session_token`;
|
|
218
235
|
this.registerOptions(options);
|
|
219
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* The active Better Auth instance. Throws before `init()` in deferred
|
|
239
|
+
* instance mode (constructed with `secret` instead of `auth`).
|
|
240
|
+
*/
|
|
241
|
+
get auth() {
|
|
242
|
+
if (!this.#auth) {
|
|
243
|
+
throw new Error(
|
|
244
|
+
"MastraAuthBetterAuth is not initialized \u2014 init() must run first (or pass a configured `auth` instance)."
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
return this.#auth;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Session cookie name, honoring Better Auth's `cookiePrefix`, a caller
|
|
251
|
+
* override via `advanced.cookies.session_token.name`, and the `__Secure-`
|
|
252
|
+
* prefix Better Auth applies when secure cookies are active.
|
|
253
|
+
*/
|
|
254
|
+
get sessionCookieName() {
|
|
255
|
+
const options = this.#auth?.options;
|
|
256
|
+
const advanced = options?.advanced;
|
|
257
|
+
const prefix = advanced?.cookiePrefix ?? "better-auth";
|
|
258
|
+
const secure = advanced?.useSecureCookies ?? options?.baseURL?.startsWith("https://") ?? false;
|
|
259
|
+
const baseName = advanced?.cookies?.session_token?.name ?? `${prefix}.session_token`;
|
|
260
|
+
return `${secure ? "__Secure-" : ""}${baseName}`;
|
|
261
|
+
}
|
|
262
|
+
// ============================================
|
|
263
|
+
// IAuthInit implementation
|
|
264
|
+
// ============================================
|
|
265
|
+
/**
|
|
266
|
+
* One-time host initialization. In deferred instance mode (no `auth` in the
|
|
267
|
+
* options) this builds the provider-owned `betterAuth()` instance on the
|
|
268
|
+
* host's auth database; schema migrations then run lazily behind a
|
|
269
|
+
* once-per-process latch on first use.
|
|
270
|
+
*
|
|
271
|
+
* Bring-your-own `auth` instances skip construction entirely — the caller
|
|
272
|
+
* owns their database and migrations.
|
|
273
|
+
*/
|
|
274
|
+
async init(ctx) {
|
|
275
|
+
this.#crossSite = (ctx.allowedOrigins?.length ?? 0) > 0;
|
|
276
|
+
if (this.#auth) return;
|
|
277
|
+
const authDb = ctx.database;
|
|
278
|
+
if (!authDb) {
|
|
279
|
+
throw new Error(
|
|
280
|
+
"MastraAuthBetterAuth needs a database to build its own better-auth instance, but the host passed none. Use a storage backend that exposes an auth database, or pass your own configured `auth` instance."
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
const database = authDb.dialect === "postgres" ? authDb.pool : authDb.dialect === "libsql" ? {
|
|
284
|
+
dialect: new LibsqlDialect({ client: authDb.client }),
|
|
285
|
+
type: "sqlite"
|
|
286
|
+
} : authDb.database;
|
|
287
|
+
const allowedOrigins = ctx.allowedOrigins ?? [];
|
|
288
|
+
const options = {
|
|
289
|
+
database,
|
|
290
|
+
secret: this.#secret,
|
|
291
|
+
// All provider endpoints (sign-in/up/out/session) live under /auth/api/*,
|
|
292
|
+
// where hosts mount handleAuthRequest.
|
|
293
|
+
basePath: "/auth/api",
|
|
294
|
+
...ctx.publicUrl ? { baseURL: ctx.publicUrl } : {},
|
|
295
|
+
// Cross-origin SPA deploys: SameSite=None only lets the browser SEND the
|
|
296
|
+
// cookie — better-auth still rejects requests from origins outside its
|
|
297
|
+
// own allow-list, so the SPA origins must be trusted too.
|
|
298
|
+
...allowedOrigins.length ? { trustedOrigins: allowedOrigins } : {},
|
|
299
|
+
emailAndPassword: { enabled: true, disableSignUp: !this.signUpEnabledConfig },
|
|
300
|
+
plugins: [organization()],
|
|
301
|
+
// Cross-origin SPA deploys need SameSite=None; Secure for the browser to
|
|
302
|
+
// send the session cookie.
|
|
303
|
+
...this.#crossSite ? { advanced: { defaultCookieAttributes: { sameSite: "none", secure: true } } } : {}
|
|
304
|
+
};
|
|
305
|
+
this.#auth = betterAuth(options);
|
|
306
|
+
this.#ownsInstance = true;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Ensure better-auth's tables exist in the host database. Only for instances
|
|
310
|
+
* this provider built — bring-your-own instances manage their own migrations.
|
|
311
|
+
*/
|
|
312
|
+
async #ensureDbReady() {
|
|
313
|
+
if (!this.#ownsInstance) return;
|
|
314
|
+
this.#migrated ??= (async () => {
|
|
315
|
+
const { runMigrations } = await getMigrations(this.auth.options);
|
|
316
|
+
await runMigrations();
|
|
317
|
+
})();
|
|
318
|
+
try {
|
|
319
|
+
await this.#migrated;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
this.#migrated = void 0;
|
|
322
|
+
console.warn("[BetterAuth] Failed to run auth schema migrations; auth stays unavailable until this succeeds.");
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// ============================================
|
|
327
|
+
// IAuthHttpHandler implementation
|
|
328
|
+
// ============================================
|
|
329
|
+
/**
|
|
330
|
+
* Proxy a raw HTTP request to Better Auth's own API surface
|
|
331
|
+
* (sign-in/up/out/session). Hosts mount this under `/auth/api/*`.
|
|
332
|
+
*/
|
|
333
|
+
async handleAuthRequest(request) {
|
|
334
|
+
try {
|
|
335
|
+
await this.#ensureDbReady();
|
|
336
|
+
} catch {
|
|
337
|
+
return new Response(JSON.stringify({ error: "auth_unavailable" }), {
|
|
338
|
+
status: 503,
|
|
339
|
+
headers: { "content-type": "application/json" }
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return this.auth.handler(request);
|
|
343
|
+
}
|
|
344
|
+
// ============================================
|
|
345
|
+
// IOrganizationsProvider implementation
|
|
346
|
+
// ============================================
|
|
347
|
+
/**
|
|
348
|
+
* Ensure the user belongs to an organization, mirroring the WorkOS
|
|
349
|
+
* personal-org bootstrap on better-auth's organization tables:
|
|
350
|
+
* ≥1 membership → first org id; 0 → create a personal org with an
|
|
351
|
+
* idempotent slug derived from the user id.
|
|
352
|
+
*
|
|
353
|
+
* Concurrent/retried first logins recover via the unique slug instead of
|
|
354
|
+
* creating duplicates. Slug alone is NOT proof of ownership though: the
|
|
355
|
+
* organization API is reachable by any authenticated user, so an attacker
|
|
356
|
+
* could squat `personal-<victimId>`. The slug-matched org is only adopted
|
|
357
|
+
* when nobody else is a member; otherwise a fresh org with an unguessable
|
|
358
|
+
* slug is created instead.
|
|
359
|
+
*
|
|
360
|
+
* Best-effort: any failure is swallowed and leaves the user no-org.
|
|
361
|
+
*/
|
|
362
|
+
async ensureOrganization(userId) {
|
|
363
|
+
const cached = this.#orgCache.get(userId);
|
|
364
|
+
if (cached) return cached;
|
|
365
|
+
try {
|
|
366
|
+
await this.#ensureDbReady();
|
|
367
|
+
const ctx = await this.getAuthContext();
|
|
368
|
+
if (!ctx) return void 0;
|
|
369
|
+
const memberships = await ctx.adapter.findMany({
|
|
370
|
+
model: "member",
|
|
371
|
+
where: [{ field: "userId", value: userId }]
|
|
372
|
+
});
|
|
373
|
+
const firstExisting = memberships.find((m) => m.organizationId)?.organizationId;
|
|
374
|
+
if (firstExisting) {
|
|
375
|
+
this.#orgCache.set(userId, firstExisting);
|
|
376
|
+
return firstExisting;
|
|
377
|
+
}
|
|
378
|
+
const userRecord = await ctx.internalAdapter.findUserById(userId).catch(() => null);
|
|
379
|
+
const label = userRecord?.email ?? userRecord?.name ?? userId;
|
|
380
|
+
const orgName = `${label}'s org`;
|
|
381
|
+
const orgData = () => ({
|
|
382
|
+
name: orgName,
|
|
383
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
384
|
+
metadata: JSON.stringify({ mastraPersonalOrg: "true" })
|
|
385
|
+
});
|
|
386
|
+
const slug = `personal-${userId}`;
|
|
387
|
+
let organizationId;
|
|
388
|
+
try {
|
|
389
|
+
const created = await ctx.adapter.create({
|
|
390
|
+
model: "organization",
|
|
391
|
+
data: { ...orgData(), slug }
|
|
392
|
+
});
|
|
393
|
+
organizationId = created.id;
|
|
394
|
+
} catch (error) {
|
|
395
|
+
const existing = await ctx.adapter.findOne({
|
|
396
|
+
model: "organization",
|
|
397
|
+
where: [{ field: "slug", value: slug }]
|
|
398
|
+
});
|
|
399
|
+
if (!existing) throw error;
|
|
400
|
+
const existingMembers = await ctx.adapter.findMany({
|
|
401
|
+
model: "member",
|
|
402
|
+
where: [{ field: "organizationId", value: existing.id }]
|
|
403
|
+
});
|
|
404
|
+
const foreignMember = existingMembers.some((m) => m.userId !== userId);
|
|
405
|
+
if (foreignMember) {
|
|
406
|
+
const fallback = await ctx.adapter.create({
|
|
407
|
+
model: "organization",
|
|
408
|
+
data: { ...orgData(), slug: `personal-${userId}-${crypto.randomUUID()}` }
|
|
409
|
+
});
|
|
410
|
+
organizationId = fallback.id;
|
|
411
|
+
} else {
|
|
412
|
+
organizationId = existing.id;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
await ctx.adapter.create({
|
|
417
|
+
model: "member",
|
|
418
|
+
data: { organizationId, userId, role: "owner", createdAt: /* @__PURE__ */ new Date() }
|
|
419
|
+
});
|
|
420
|
+
} catch (error) {
|
|
421
|
+
const member = await ctx.adapter.findOne({
|
|
422
|
+
model: "member",
|
|
423
|
+
where: [
|
|
424
|
+
{ field: "organizationId", value: organizationId },
|
|
425
|
+
{ field: "userId", value: userId }
|
|
426
|
+
]
|
|
427
|
+
});
|
|
428
|
+
if (!member) throw error;
|
|
429
|
+
}
|
|
430
|
+
this.#orgCache.set(userId, organizationId);
|
|
431
|
+
return organizationId;
|
|
432
|
+
} catch (error) {
|
|
433
|
+
console.warn(
|
|
434
|
+
`[BetterAuth] Failed to bootstrap personal organization for user ${userId}. The user will see organization_required until this succeeds.`,
|
|
435
|
+
error
|
|
436
|
+
);
|
|
437
|
+
return void 0;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Whether the user holds an admin-equivalent role (`owner` or `admin`) in
|
|
442
|
+
* the organization. Provider errors resolve to `false`.
|
|
443
|
+
*/
|
|
444
|
+
async isOrganizationAdmin(organizationId, userId) {
|
|
445
|
+
try {
|
|
446
|
+
await this.#ensureDbReady();
|
|
447
|
+
const ctx = await this.getAuthContext();
|
|
448
|
+
if (!ctx) return false;
|
|
449
|
+
const membership = await ctx.adapter.findOne({
|
|
450
|
+
model: "member",
|
|
451
|
+
where: [
|
|
452
|
+
{ field: "organizationId", value: organizationId },
|
|
453
|
+
{ field: "userId", value: userId }
|
|
454
|
+
]
|
|
455
|
+
});
|
|
456
|
+
return membership?.role === "owner" || membership?.role === "admin";
|
|
457
|
+
} catch {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
220
461
|
/**
|
|
221
462
|
* Check if sign-up is enabled.
|
|
222
463
|
* Implements ICredentialsProvider.isSignUpEnabled.
|
|
@@ -232,13 +473,21 @@ var MastraAuthBetterAuth = class extends MastraAuthProvider {
|
|
|
232
473
|
* Get current user from request.
|
|
233
474
|
* Implements IUserProvider for EE user awareness in Studio.
|
|
234
475
|
*
|
|
476
|
+
* Supports both cookie-based sessions and `Authorization: Bearer <token>`
|
|
477
|
+
* requests (e.g. API clients using the token returned by `signIn`).
|
|
478
|
+
*
|
|
235
479
|
* @param request - Incoming HTTP request
|
|
236
480
|
* @returns EE User object or null if not authenticated
|
|
237
481
|
*/
|
|
238
482
|
async getCurrentUser(request) {
|
|
239
483
|
try {
|
|
484
|
+
await this.#ensureDbReady();
|
|
485
|
+
const headers = new Headers(request.headers);
|
|
486
|
+
const authHeader = headers.get("Authorization");
|
|
487
|
+
const bearerToken = authHeader && authHeader.slice(0, 7).toLowerCase() === "bearer " ? authHeader.slice(7).trim() : void 0;
|
|
488
|
+
await this.ensureSessionCookie(headers, bearerToken);
|
|
240
489
|
const result = await this.auth.api.getSession({
|
|
241
|
-
headers
|
|
490
|
+
headers
|
|
242
491
|
});
|
|
243
492
|
if (!result?.user) return null;
|
|
244
493
|
return mapBetterAuthUserToEEUser(result.user);
|
|
@@ -250,18 +499,32 @@ var MastraAuthBetterAuth = class extends MastraAuthProvider {
|
|
|
250
499
|
* Get user by ID.
|
|
251
500
|
* Implements IUserProvider for EE user awareness.
|
|
252
501
|
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
* direct database access in a subclass.
|
|
502
|
+
* Uses Better Auth's internal adapter to look up the user record,
|
|
503
|
+
* so it works with whichever database Better Auth is configured with.
|
|
256
504
|
*
|
|
257
505
|
* @param userId - User identifier
|
|
258
506
|
* @returns EE User object or null if not found
|
|
259
507
|
*/
|
|
260
|
-
async getUser(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
508
|
+
async getUser(userId) {
|
|
509
|
+
try {
|
|
510
|
+
const ctx = await this.getAuthContext();
|
|
511
|
+
if (!ctx) return null;
|
|
512
|
+
const user = await ctx.internalAdapter.findUserById(userId);
|
|
513
|
+
if (!user) return null;
|
|
514
|
+
return mapBetterAuthUserToEEUser(user);
|
|
515
|
+
} catch {
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Get multiple users by ID.
|
|
521
|
+
* Optional IUserProvider method used for batch author enrichment.
|
|
522
|
+
*
|
|
523
|
+
* @param userIds - User identifiers
|
|
524
|
+
* @returns EE User objects (null for missing users, order preserved)
|
|
525
|
+
*/
|
|
526
|
+
async getUsers(userIds) {
|
|
527
|
+
return Promise.all(userIds.map((userId) => this.getUser(userId)));
|
|
265
528
|
}
|
|
266
529
|
/**
|
|
267
530
|
* Get URL to user's profile page.
|
|
@@ -270,11 +533,51 @@ var MastraAuthBetterAuth = class extends MastraAuthProvider {
|
|
|
270
533
|
getUserProfileUrl(user) {
|
|
271
534
|
return `/profile/${user.id}`;
|
|
272
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* Get the resolved Better Auth context, or null when unavailable
|
|
538
|
+
* (e.g. a partial mock without `$context`).
|
|
539
|
+
*/
|
|
540
|
+
async getAuthContext() {
|
|
541
|
+
try {
|
|
542
|
+
return await Promise.resolve(this.auth.$context) ?? null;
|
|
543
|
+
} catch {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Ensure the Cookie header on `headers` carries a Better Auth session cookie
|
|
549
|
+
* for the given token.
|
|
550
|
+
*
|
|
551
|
+
* Better Auth's `getSession` reads the session from a *signed* cookie
|
|
552
|
+
* (`<token>.<HMAC-SHA256 signature>`), while `signIn`/`signUp` return the
|
|
553
|
+
* raw unsigned token. Mirroring Better Auth's bearer plugin, unsigned tokens
|
|
554
|
+
* are signed with the instance secret before being set as the session cookie.
|
|
555
|
+
*/
|
|
556
|
+
async ensureSessionCookie(headers, token) {
|
|
557
|
+
if (!token) return;
|
|
558
|
+
const ctx = await this.getAuthContext();
|
|
559
|
+
const cookieName = ctx?.authCookies.sessionToken.name ?? this.sessionCookieName;
|
|
560
|
+
const secret = ctx?.secret;
|
|
561
|
+
const cookieHeader = headers.get("Cookie");
|
|
562
|
+
const hasSessionCookie = !!cookieHeader?.split(";").some((pair) => {
|
|
563
|
+
const [key] = pair.trim().split("=");
|
|
564
|
+
return key?.trim() === cookieName;
|
|
565
|
+
});
|
|
566
|
+
if (hasSessionCookie) return;
|
|
567
|
+
let cookieValue = token.includes(".") ? token.includes("%") ? tryDecode(token) : token : token;
|
|
568
|
+
if (!token.includes(".") && secret) {
|
|
569
|
+
cookieValue = `${token}.${await makeSignature(token, secret)}`;
|
|
570
|
+
}
|
|
571
|
+
const existingCookies = cookieHeader ? `${cookieHeader}; ` : "";
|
|
572
|
+
headers.set("Cookie", `${existingCookies}${cookieName}=${encodeURIComponent(cookieValue)}`);
|
|
573
|
+
}
|
|
273
574
|
/**
|
|
274
575
|
* Authenticate a bearer token by verifying the session with Better Auth.
|
|
275
576
|
*
|
|
276
577
|
* This method extracts the session from the request headers using
|
|
277
|
-
* Better Auth's `api.getSession()` endpoint.
|
|
578
|
+
* Better Auth's `api.getSession()` endpoint. Raw (unsigned) session tokens —
|
|
579
|
+
* as returned by `signIn`/`signUp` — are signed before being passed to
|
|
580
|
+
* Better Auth as a session cookie, matching the bearer plugin's semantics.
|
|
278
581
|
*
|
|
279
582
|
* @param token - The bearer token (session token) to authenticate
|
|
280
583
|
* @param request - The request containing headers
|
|
@@ -282,19 +585,13 @@ var MastraAuthBetterAuth = class extends MastraAuthProvider {
|
|
|
282
585
|
*/
|
|
283
586
|
async authenticateToken(token, request) {
|
|
284
587
|
try {
|
|
588
|
+
await this.#ensureDbReady();
|
|
285
589
|
const headers = new Headers();
|
|
286
590
|
const cookieHeader = getRequestHeader2(request, "Cookie");
|
|
287
591
|
if (cookieHeader) {
|
|
288
592
|
headers.set("Cookie", cookieHeader);
|
|
289
593
|
}
|
|
290
|
-
|
|
291
|
-
const [key] = pair.trim().split("=");
|
|
292
|
-
return key?.trim() === this.sessionCookieName;
|
|
293
|
-
});
|
|
294
|
-
if (token && !hasSessionCookie) {
|
|
295
|
-
const existingCookies = cookieHeader ? `${cookieHeader}; ` : "";
|
|
296
|
-
headers.set("Cookie", `${existingCookies}${this.sessionCookieName}=${token}`);
|
|
297
|
-
}
|
|
594
|
+
await this.ensureSessionCookie(headers, token);
|
|
298
595
|
const result = await this.auth.api.getSession({
|
|
299
596
|
headers
|
|
300
597
|
});
|
|
@@ -414,9 +711,10 @@ var MastraAuthBetterAuth = class extends MastraAuthProvider {
|
|
|
414
711
|
* Clears Better Auth's default session cookies.
|
|
415
712
|
*/
|
|
416
713
|
getClearSessionHeaders() {
|
|
714
|
+
const sameSite = this.#crossSite ? "None; Secure" : "Lax";
|
|
417
715
|
const cookies = [
|
|
418
|
-
`${this.sessionCookieName}=; Path=/; HttpOnly; SameSite
|
|
419
|
-
`${this.sessionCookieName}_sig=; Path=/; HttpOnly; SameSite
|
|
716
|
+
`${this.sessionCookieName}=; Path=/; HttpOnly; SameSite=${sameSite}; Max-Age=0`,
|
|
717
|
+
`${this.sessionCookieName}_sig=; Path=/; HttpOnly; SameSite=${sameSite}; Max-Age=0`
|
|
420
718
|
];
|
|
421
719
|
return {
|
|
422
720
|
"Set-Cookie": cookies.join(", ")
|