[GH-ISSUE #7454] listSessions returns sessions without id field when using secondaryStorage (Redis) #28139

Closed
opened 2026-04-17 19:32:45 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @phuctm97 on GitHub (Jan 18, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/7454

Originally assigned to: @bytaesu on GitHub.

Description

When using secondaryStorage (Redis), the authClient.listSessions() API returns sessions without the id field, despite the TypeScript type definitions indicating that id should be present.

This appears to be related to #6993 - the root cause is likely that sessions are stored in secondary storage (KV/Redis) before the database generates the id, so the cached sessions never receive the id field.

Expected Behavior

listSessions() should return sessions with all fields including id:

const { data: sessions } = await authClient.listSessions();
// sessions[0].id should be defined

Actual Behavior

Sessions are returned without the id field:

const { data: sessions } = await authClient.listSessions();
console.log(sessions[0].id); // undefined
console.log(sessions[0]); // { token: "...", userId: "...", expiresAt: "...", ... } - no id field

TypeScript does not catch this because the type definition includes id as a required field.

Steps to Reproduce

  1. Configure better-auth with secondaryStorage (Redis):
export const auth = betterAuth({
  database: drizzleAdapter(database, { provider: "pg" }),
  secondaryStorage: {
    get: (key) => redis.get(key),
    set: async (key, value, ttl) => {
      await (typeof ttl === "number"
        ? redis.set(key, value, { EX: ttl })
        : redis.set(key, value));
    },
    delete: async (key) => {
      await redis.del(key);
    },
  },
  // ... other config
});
  1. Authenticate a user (creates a session)
  2. Call authClient.listSessions()
  3. Observe that returned sessions have no id field

Root Cause Analysis

Based on #6993, the issue is in the session creation flow:

  1. Session data is stored in secondaryStorage (Redis) before database insertion
  2. Database create operation generates the id
  3. Secondary storage is never updated with the generated id
  4. When listSessions reads from cache, it gets session data without id

Impact

  • Cannot use session id for operations like revokeSession({ id: session.id })
  • Type safety is compromised (runtime values don't match TypeScript types)
  • Related to OAuth provider issues in #6993

Environment

  • better-auth: ^1.4.15
  • @better-auth/cli: ^1.4.15
  • Runtime: Node.js
  • Secondary storage: Redis (using redis npm package v5.x)
  • #6993 - Session ID missing in KV storage when using secondaryStorage + storeSessionInDatabase
  • #7281 - authClient.listSessions returns duplicated sessions (same ID)
Originally created by @phuctm97 on GitHub (Jan 18, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/7454 Originally assigned to: @bytaesu on GitHub. ## Description When using `secondaryStorage` (Redis), the `authClient.listSessions()` API returns sessions without the `id` field, despite the TypeScript type definitions indicating that `id` should be present. This appears to be related to #6993 - the root cause is likely that sessions are stored in secondary storage (KV/Redis) **before** the database generates the `id`, so the cached sessions never receive the `id` field. ## Expected Behavior `listSessions()` should return sessions with all fields including `id`: ```typescript const { data: sessions } = await authClient.listSessions(); // sessions[0].id should be defined ``` ## Actual Behavior Sessions are returned without the `id` field: ```typescript const { data: sessions } = await authClient.listSessions(); console.log(sessions[0].id); // undefined console.log(sessions[0]); // { token: "...", userId: "...", expiresAt: "...", ... } - no id field ``` TypeScript does not catch this because the type definition includes `id` as a required field. ## Steps to Reproduce 1. Configure better-auth with secondaryStorage (Redis): ```typescript export const auth = betterAuth({ database: drizzleAdapter(database, { provider: "pg" }), secondaryStorage: { get: (key) => redis.get(key), set: async (key, value, ttl) => { await (typeof ttl === "number" ? redis.set(key, value, { EX: ttl }) : redis.set(key, value)); }, delete: async (key) => { await redis.del(key); }, }, // ... other config }); ``` 2. Authenticate a user (creates a session) 3. Call `authClient.listSessions()` 4. Observe that returned sessions have no `id` field ## Root Cause Analysis Based on #6993, the issue is in the session creation flow: 1. Session data is stored in secondaryStorage (Redis) **before** database insertion 2. Database `create` operation generates the `id` 3. Secondary storage is **never updated** with the generated `id` 4. When `listSessions` reads from cache, it gets session data without `id` ## Impact - Cannot use session `id` for operations like `revokeSession({ id: session.id })` - Type safety is compromised (runtime values don't match TypeScript types) - Related to OAuth provider issues in #6993 ## Environment - better-auth: ^1.4.15 - @better-auth/cli: ^1.4.15 - Runtime: Node.js - Secondary storage: Redis (using `redis` npm package v5.x) ## Related Issues - #6993 - Session ID missing in KV storage when using secondaryStorage + storeSessionInDatabase - #7281 - authClient.listSessions returns duplicated sessions (same ID)
GiteaMirror added the lockedbug labels 2026-04-17 19:32:46 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 18, 2026):

Thank you for bringing up the issue! It seems you're experiencing problems with the authClient.listSessions() API returning sessions without the id field when using secondaryStorage (Redis).

This behavior appears to be related to how sessions are stored in Redis. Essentially, the session data is being cached in secondary storage before the database has a chance to generate the id. As a result, the id field is missing when the sessions are retrieved later.

There is an open issue (as noted in #6993) that discusses this specific behavior, and it outlines the root cause and expected functionality. A recommended next step is to check the latest updates on that issue to see if any fixes or workarounds have been proposed.

In the meantime, you may want to implement a solution that ensures the session data is updated in Redis after the database generates the id.

Would you like to know about potential workarounds or alternative strategies for handling session management in this case? Feel free to ask!

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3765363977 --> @better-auth-agent[bot] commented on GitHub (Jan 18, 2026): Thank you for bringing up the issue! It seems you're experiencing problems with the `authClient.listSessions()` API returning sessions without the `id` field when using `secondaryStorage` (Redis). This behavior appears to be related to how sessions are stored in Redis. Essentially, the session data is being cached in secondary storage before the database has a chance to generate the `id`. As a result, the `id` field is missing when the sessions are retrieved later. There is an open issue (as noted in #6993) that discusses this specific behavior, and it outlines the root cause and expected functionality. A recommended next step is to check the latest updates on that issue to see if any fixes or workarounds have been proposed. In the meantime, you may want to implement a solution that ensures the session data is updated in Redis after the database generates the `id`. Would you like to know about potential workarounds or alternative strategies for handling session management in this case? Feel free to ask! _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@dosubot[bot] commented on GitHub (Jan 18, 2026):

This is a known issue: when using secondaryStorage (like Redis), sessions are cached before the database generates the id, so the cached session objects never include the id field. The cache is never updated after the database insert, which means listSessions returns sessions without id, breaking type safety and downstream operations like revokeSession. This is confirmed by both the code and multiple issues, including #6993 and #2007.

The relevant code path is: session data is written to secondaryStorage in a hook before the DB insert, so the id is missing in the cached object. When listSessions runs, it reads from the cache, so you get sessions without id (source).

There are two main workarounds:

  1. Update secondaryStorage after the DB create, so the cached session includes the id (example code).
  2. Pre-generate the session id before storing in both the DB and secondaryStorage (example code).

There is no built-in fix as of ^1.4.15; you’ll need to patch your session creation logic to ensure the id is present in the cached session. Recent PRs like #6988 improve session update syncing, but do not fix the initial missing id at creation.

If you need an immediate fix, update your session creation flow to write the session (with id) to secondaryStorage after the DB insert.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3765367604 --> @dosubot[bot] commented on GitHub (Jan 18, 2026): <!-- Answer --> This is a known issue: when using secondaryStorage (like Redis), sessions are cached before the database generates the id, so the cached session objects never include the id field. The cache is never updated after the database insert, which means listSessions returns sessions without id, breaking type safety and downstream operations like revokeSession. This is confirmed by both the code and multiple issues, including [#6993](https://github.com/better-auth/better-auth/issues/6993) and [#2007](https://github.com/better-auth/better-auth/issues/2007). The relevant code path is: session data is written to secondaryStorage in a hook before the DB insert, so the id is missing in the cached object. When listSessions runs, it reads from the cache, so you get sessions without id ([source](https://github.com/better-auth/better-auth/blob/308f8ae14e3547c8f2ebf220a6e0cf96f0e42b87/packages/better-auth/src/db/internal-adapter.ts#L150-L376)). There are two main workarounds: 1. Update secondaryStorage after the DB create, so the cached session includes the id ([example code](https://github.com/better-auth/better-auth/issues/6993#issuecomment-3690246269)). 2. Pre-generate the session id before storing in both the DB and secondaryStorage ([example code](https://github.com/better-auth/better-auth/issues/6993#issuecomment-3690246269)). There is no built-in fix as of ^1.4.15; you’ll need to patch your session creation logic to ensure the id is present in the cached session. Recent PRs like [#6988](https://github.com/better-auth/better-auth/pull/6988) improve session update syncing, but do not fix the initial missing id at creation. If you need an immediate fix, update your session creation flow to write the session (with id) to secondaryStorage after the DB insert. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/94b02a3d-e344-48bf-844b-d97b9510f6b0?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/94b02a3d-e344-48bf-844b-d97b9510f6b0?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/94b02a3d-e344-48bf-844b-d97b9510f6b0?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/94b02a3d-e344-48bf-844b-d97b9510f6b0?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/94b02a3d-e344-48bf-844b-d97b9510f6b0?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/94b02a3d-e344-48bf-844b-d97b9510f6b0?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/94b02a3d-e344-48bf-844b-d97b9510f6b0?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20known%20issue%3A%20when%20using%20secondaryStorage%20%28like%20Redis%29%2C%20sessions%20are%20cached%20before%20the%20database%20generates%20the%20id%2C%20so%20the%20cached%20session%20objects%20never%20include%20the%20id%20field.%20The%20cache%20is%20never%20updated%20after%20the%20database%20insert%2C%20which%20means%20listSessions%20returns%20sessions%20without%20id%2C%20breaking%20type%20safety%20and%20downstream%20operations%20like%20revokeSession.%20This%20is%20confirmed%20by%20both%20the%20code%20and%20multiple%20issues%2C%20including%20%5B%236993%5D%28https%3A//github.com/better-auth/better-auth/issues/6993%29%20and%20%5B%232007%5D%28https%3A//github.com/better-auth/better-auth/issues/2007%29.%0A%0AThe%20relevant%20code%20path%20is%3A%20session%20data%20is%20written%20to%20secondaryStorage%20in%20a%20hook%20before%20the%20DB%20insert%2C%20so%20the%20id%20is%20missing%20in%20the%20cached%20object.%20When%20listSessions%20runs%2C%20it%20reads%20from%20the%20cache%2C%20so%20you%20get%20sessions%20without%20id%20%28%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/blob/308f8ae14e3547c8f2ebf220a6e0cf96f0e42b87/packages/better-auth/src/db/internal-adapter.ts%23L150-L376%29%29.%0A%0AThere%20are%20two%20main%20workarounds%3A%0A1.%20Update%20secondaryStorage%20after%20the%20DB%20create%2C%20so%20the%20cached%20session%20includes%20the%20id%20%28%5Bexample%20code%5D%28https%3A//github.com/better-auth/better-auth/issues/6993%23issuecomment-3690246269%29%29.%0A2.%20Pre-generate%20the%20session%20id%20before%20storing%20in%20both%20the%20DB%20and%20secondaryStorage%20%28%5Bexample%20code%5D%28https%3A//github.com/better-auth/better-auth/issues/6993%23issuecomment-3690246269%29%29.%0A%0AThere%20is%20no%20built-in%20fix%20as%20of%20%5E1.4.15%3B%20you%E2%80%99ll%20need%20to%20patch%20your%20session%20creation%20logic%20to%20ensure%20the%20id%20is%20present%20in%20the%20cached%20session.%20Recent%20PRs%20like%20%5B%236988%5D%28https%3A//github.com/better-auth/better-auth/pull/6988%29%20improve%20session%20update%20syncing%2C%20but%20do%20not%20fix%20the%20initial%20missing%20id%20at%20creation.%0A%0AIf%20you%20need%20an%20immediate%20fix%2C%20update%20your%20session%20creation%20flow%20to%20write%20the%20session%20%28with%20id%29%20to%20secondaryStorage%20after%20the%20DB%20insert.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/7454)
Author
Owner

@ping-maxwell commented on GitHub (Jan 18, 2026):

hey @phuctm97 how are you creating sessions initially? For example, are you using sign-in via email?

<!-- gh-comment-id:3765457146 --> @ping-maxwell commented on GitHub (Jan 18, 2026): hey @phuctm97 how are you creating sessions initially? For example, are you using sign-in via email?
Author
Owner

@bytaesu commented on GitHub (Jan 19, 2026):

I think this is related to this PR. I'll resolve the conflicts.

<!-- gh-comment-id:3767126685 --> @bytaesu commented on GitHub (Jan 19, 2026): I think this is related to this PR. I'll resolve the conflicts. - https://github.com/better-auth/better-auth/pull/7019
Author
Owner

@phuctm97 commented on GitHub (Jan 19, 2026):

hey @phuctm97 how are you creating sessions initially? For example, are you using sign-in via email?

I sign up and sign in with email password. I also have bearer plugin configured.

<!-- gh-comment-id:3767812596 --> @phuctm97 commented on GitHub (Jan 19, 2026): > hey [@phuctm97](https://github.com/phuctm97) how are you creating sessions initially? For example, are you using sign-in via email? I sign up and sign in with email password. I also have bearer plugin configured.
Author
Owner

@phuctm97 commented on GitHub (Jan 19, 2026):

I think this is related to this PR. I'll resolve the conflicts.

I don't have storeSessionInDatabase enabled, I want to keep sessions in Redis only.

<!-- gh-comment-id:3767813855 --> @phuctm97 commented on GitHub (Jan 19, 2026): > I think this is related to this PR. I'll resolve the conflicts. > > * [fix: include session id in secondary storage when `storeSessionInDatabase` is true #7019](https://github.com/better-auth/better-auth/pull/7019) I don't have `storeSessionInDatabase` enabled, I want to keep sessions in Redis only.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#28139