Bind Better Auth sessions to devices

This commit is contained in:
2026-05-09 03:46:15 -04:00
parent 0c64a7721e
commit 2dda91c50b
6 changed files with 88 additions and 6 deletions
+20 -3
View File
@@ -213,7 +213,12 @@ describe("api controls", () => {
rateLimitKeys,
d1: testD1Database({
firstRows: [
{ id: "session-01", userId: "user-01", expiresAt: "2099-01-01T00:00:00.000Z" },
{
id: "session-01",
userId: "user-01",
expiresAt: "2099-01-01T00:00:00.000Z",
deviceId: "device-01",
},
],
queries: d1Queries,
binds: d1Binds,
@@ -223,12 +228,23 @@ describe("api controls", () => {
["GET"],
(context) =>
Promise.resolve(
jsonResponse({ user_id: context.userId, session_id: context.sessionId }, 200),
jsonResponse(
{
user_id: context.userId,
session_id: context.sessionId,
device_id: context.deviceId,
},
200,
),
),
);
assert.equal(response.status, 200);
assert.deepEqual(await response.json(), { user_id: "user-01", session_id: "session-01" });
assert.deepEqual(await response.json(), {
user_id: "user-01",
session_id: "session-01",
device_id: "device-01",
});
assert.deepEqual(rateLimitKeys, [`local:devices.list:bearer:${tokenHash}`]);
assert.deepEqual(kvReads, [authSessionCacheKvKey("local", tokenHash)]);
assert.equal(d1Queries.length, 1);
@@ -243,6 +259,7 @@ describe("api controls", () => {
"",
"user-01",
]);
assert.equal(auditEvents[0]?.blobs?.[7], "device-01");
});
it("rejects expired authenticated sessions", async () => {
+2
View File
@@ -207,6 +207,7 @@ describe("device routes", () => {
assert.ok(d1.queries[0]?.includes("INSERT INTO user_devices"));
assert.ok(d1.queries[0]?.includes("ON CONFLICT(user_id, idempotency_key) DO NOTHING"));
assert.ok(d1.queries[1]?.includes("WHERE user_id = ? AND idempotency_key = ?"));
assert.ok(d1.queries[2]?.includes("better_auth_session_device_context"));
assert.deepEqual(d1.binds[0]?.slice(0, 5), [
"user-01",
"device-01",
@@ -218,6 +219,7 @@ describe("device routes", () => {
assert.equal(typeof d1.binds[0]?.[6], "number");
assert.equal(d1.binds[0]?.[7], IDEMPOTENCY_KEY);
assert.deepEqual(d1.binds[1], ["user-01", IDEMPOTENCY_KEY]);
assert.deepEqual(d1.binds[2]?.slice(0, 3), ["session-01", "user-01", "device-01"]);
});
it("rejects invalid device registration payloads before D1 writes", async () => {
+11
View File
@@ -13,6 +13,7 @@ const EXPECTED_MIGRATIONS = [
"0004_releases.sql",
"0005_audit.sql",
"0006_better_auth.sql",
"0007_better_auth_session_device_context.sql",
];
const USER_SCOPED_TABLES = [
"user_devices",
@@ -39,6 +40,7 @@ describe("D1 migrations", () => {
"audit_events",
"better_auth_account",
"better_auth_session",
"better_auth_session_device_context",
"better_auth_user",
"better_auth_verification",
"device_approvals",
@@ -104,6 +106,15 @@ describe("D1 migrations", () => {
]),
[],
);
assert.deepEqual(
requiredColumns(databasePath, "better_auth_session_device_context", [
"session_id",
"user_id",
"device_id",
"updated_at",
]),
[],
);
});
});