[GH-ISSUE #5144] RevokeSession with secondary storage #10173

Closed
opened 2026-04-13 06:08:36 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @Girbi on GitHub (Oct 7, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5144

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Enable secondary storage and set auth with the following settings for sessions:
    session: { modelName: "sessions", storeSessionInDatabase: true, preserveSessionInDatabase: true, cookieCache: { enabled: true, maxAge: 5 * 60, // 5 minutes }, },
  2. Calling revokeSession only deletes secondary storage data, does not update expiredAt in the database, because the internalAdapter just finds and deletes any sessions, it doesnt consider the database session.

Current vs. Expected behavior

Current: revokeSession just deletes secondaryStorage and doesn't consider the database session.

Expected: revokeSession to update session inside database also, not just delete it from secondary storage, because i passed preserveSessionInDatabase: true and this means the session cannot be deleted from the database.

What version of Better Auth are you using?

1.3.27

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC Thu, 02 Oct 2025 19:26:36 +0000",
    "release": "6.16.10-arch1-1",
    "cpuCount": 12,
    "cpuModel": "AMD Ryzen 5 3600X 6-Core Processor",
    "totalMemory": "31.26 GB",
    "freeMemory": "5.01 GB"
  },
  "node": {
    "version": "v22.14.0",
    "env": "development"
  },
  "packageManager": {
    "name": "pnpm",
    "version": "10.15.0"
  },
  "frameworks": null,
  "databases": null,
  "betterAuth": {
    "version": "1.3.27",
    "config": {
      "appName": "App",
      "secret": "[REDACTED]",
      "advanced": {
        "cookiePrefix": "app"
      },
      "session": {
        "modelName": "sessions",
        "storeSessionInDatabase": true,
        "preserveSessionInDatabase": true,
        "cookieCache": {
          "enabled": true,
          "maxAge": 300
        }
      },
      "trustedOrigins": [
        "http://localhost:5173"
      ],
      "baseURL": "http://localhost:3333",
      "database": {
        "db": {},
        "type": "postgres",
        "casing": "snake"
      },
      "secondaryStorage": {},
      "rateLimit": {
        "enabled": true,
        "window": 10,
        "max": 100,
        "storage": "secondary-storage"
      },
      "emailAndPassword": {
        "enabled": true
      },
      "socialProviders": {
        "google": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]",
          "redirectURI": "http://localhost:3333/api/auth/callback/google"
        }
      },
      "user": {
        "modelName": "users",
        "additionalFields": {
          "lastActiveOrganizationId": {
            "type": "string",
            "input": false,
            "required": false
          }
        },
        "deleteUser": {
          "enabled": true
        }
      },
      "account": {
        "accountLinking": {
          "enabled": true
        },
        "modelName": "accounts"
      },
      "verification": {
        "modelName": "verifications"
      }
    }
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  appName: "App",
  secret: env.BETTER_AUTH_SECRET,
  advanced: {
    cookiePrefix: "app",
  },
  session: {
    modelName: "sessions",
    storeSessionInDatabase: true,
    preserveSessionInDatabase: true,
    cookieCache: {
      enabled: true,
      maxAge: 5 * 60, // 5 minutes
    },
  },
  trustedOrigins: [env.CLIENTSIDE_HOST],
  baseURL: env.SERVERSIDE_HOST,
  database: {
    db,
    type: "postgres",
    casing: "snake",
  },
  secondaryStorage: {
    get: async (key) => {
      return await redis.get(key);
    },
    set: async (key, value, ttl) => {
      if (ttl) await redis.set(key, value, "EX", ttl);
      else await redis.set(key, value);
    },
    delete: async (key) => {
      await redis.del(key);
    },
  },
  rateLimit: {
    enabled: true,
    window: 10,
    max: 100,
    storage: "secondary-storage",
  },
  emailAndPassword: {
    enabled: true,
  },
 // others not relevant
);

Additional context

The /revoke-session route has to be modified to take into consideration the issues mentioned above

Originally created by @Girbi on GitHub (Oct 7, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5144 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Enable secondary storage and set auth with the following settings for sessions: `session: { modelName: "sessions", storeSessionInDatabase: true, preserveSessionInDatabase: true, cookieCache: { enabled: true, maxAge: 5 * 60, // 5 minutes }, },` 2. Calling revokeSession only deletes secondary storage data, does not update expiredAt in the database, because the internalAdapter just finds and deletes any sessions, it doesnt consider the database session. ### Current vs. Expected behavior Current: revokeSession just deletes secondaryStorage and doesn't consider the database session. Expected: revokeSession to update session inside database also, not just delete it from secondary storage, because i passed `preserveSessionInDatabase: true` and this means the session cannot be deleted from the database. ### What version of Better Auth are you using? 1.3.27 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC Thu, 02 Oct 2025 19:26:36 +0000", "release": "6.16.10-arch1-1", "cpuCount": 12, "cpuModel": "AMD Ryzen 5 3600X 6-Core Processor", "totalMemory": "31.26 GB", "freeMemory": "5.01 GB" }, "node": { "version": "v22.14.0", "env": "development" }, "packageManager": { "name": "pnpm", "version": "10.15.0" }, "frameworks": null, "databases": null, "betterAuth": { "version": "1.3.27", "config": { "appName": "App", "secret": "[REDACTED]", "advanced": { "cookiePrefix": "app" }, "session": { "modelName": "sessions", "storeSessionInDatabase": true, "preserveSessionInDatabase": true, "cookieCache": { "enabled": true, "maxAge": 300 } }, "trustedOrigins": [ "http://localhost:5173" ], "baseURL": "http://localhost:3333", "database": { "db": {}, "type": "postgres", "casing": "snake" }, "secondaryStorage": {}, "rateLimit": { "enabled": true, "window": 10, "max": 100, "storage": "secondary-storage" }, "emailAndPassword": { "enabled": true }, "socialProviders": { "google": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]", "redirectURI": "http://localhost:3333/api/auth/callback/google" } }, "user": { "modelName": "users", "additionalFields": { "lastActiveOrganizationId": { "type": "string", "input": false, "required": false } }, "deleteUser": { "enabled": true } }, "account": { "accountLinking": { "enabled": true }, "modelName": "accounts" }, "verification": { "modelName": "verifications" } } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ appName: "App", secret: env.BETTER_AUTH_SECRET, advanced: { cookiePrefix: "app", }, session: { modelName: "sessions", storeSessionInDatabase: true, preserveSessionInDatabase: true, cookieCache: { enabled: true, maxAge: 5 * 60, // 5 minutes }, }, trustedOrigins: [env.CLIENTSIDE_HOST], baseURL: env.SERVERSIDE_HOST, database: { db, type: "postgres", casing: "snake", }, secondaryStorage: { get: async (key) => { return await redis.get(key); }, set: async (key, value, ttl) => { if (ttl) await redis.set(key, value, "EX", ttl); else await redis.set(key, value); }, delete: async (key) => { await redis.del(key); }, }, rateLimit: { enabled: true, window: 10, max: 100, storage: "secondary-storage", }, emailAndPassword: { enabled: true, }, // others not relevant ); ``` ### Additional context The /revoke-session route has to be modified to take into consideration the issues mentioned above
GiteaMirror added the lockedbug labels 2026-04-13 06:08:36 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Oct 7, 2025):

Hi @Girbi! I'm Dosu and I’m helping the better-auth team.

You're correct—when using both secondary storage and preserveSessionInDatabase, revokeSession currently only deletes the session from secondary storage and does not update or expire the session in the database. This is a known limitation and has been confirmed by other users and maintainers as well. The intended behavior with preserveSessionInDatabase is to mark the session as expired (e.g., by setting expiredAt), not to delete it, but the internal adapter logic does not handle this by default. As a result, revoked sessions remain active in the database and are not properly invalidated (reference, reference).

Currently, the recommended workaround is to use a custom hook or direct database update in your /revoke-session route to set expiredAt (or a similar field) on the session record in your database when you revoke a session. There is no built-in fix for this in the latest release, so manual intervention is required to ensure sessions are properly marked as expired in the database when preserveSessionInDatabase is true (reference).

If you want an example of how to implement this workaround (e.g., using a Better Auth hook or a direct DB update), let me know!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3376405962 --> @dosubot[bot] commented on GitHub (Oct 7, 2025): <!-- Greeting --> Hi @Girbi! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> You're correct—when using both secondary storage and preserveSessionInDatabase, revokeSession currently only deletes the session from secondary storage and does not update or expire the session in the database. This is a known limitation and has been confirmed by other users and maintainers as well. The intended behavior with preserveSessionInDatabase is to mark the session as expired (e.g., by setting expiredAt), not to delete it, but the internal adapter logic does not handle this by default. As a result, revoked sessions remain active in the database and are not properly invalidated ([reference](https://github.com/better-auth/better-auth/issues/1178), [reference](https://github.com/better-auth/better-auth/issues/2127)). Currently, the recommended workaround is to use a custom hook or direct database update in your /revoke-session route to set expiredAt (or a similar field) on the session record in your database when you revoke a session. There is no built-in fix for this in the latest release, so manual intervention is required to ensure sessions are properly marked as expired in the database when preserveSessionInDatabase is true ([reference](https://github.com/better-auth/better-auth/issues/2127)). If you want an example of how to implement this workaround (e.g., using a Better Auth hook or a direct DB update), let me know! <!-- 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/9750b586-dc14-40c2-a71b-159a92aadb4c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/9750b586-dc14-40c2-a71b-159a92aadb4c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/9750b586-dc14-40c2-a71b-159a92aadb4c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/9750b586-dc14-40c2-a71b-159a92aadb4c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/9750b586-dc14-40c2-a71b-159a92aadb4c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/9750b586-dc14-40c2-a71b-159a92aadb4c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/9750b586-dc14-40c2-a71b-159a92aadb4c?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&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/5144)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10173