[GH-ISSUE #993] session.create.before Hook Does Not Correctly Handle data Property in Return Value #17171

Closed
opened 2026-04-15 15:09:54 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @wh5938316 on GitHub (Dec 23, 2024).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/993

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

First, I enabled secondary storage.

When using the session.create.before hook, returning additional session fields via the data property in the return value does not store those fields in Redis. However, directly modifying the session object works as expected.

According to the documentation, session.create.before is expected to accept the returned modified session and store it in the database. However, in practice, only directly modifying the reference of the passed-in session object takes effect. This behavior is inconsistent with the documentation. Is this the intended behavior?

Current vs. Expected behavior

  1. Use the following before hook configuration:

    session: {
      create: {
        before: async (session) => {
          const teams = await findAllUserTeams(drizzle, session.userId);
          const activeTeamId = teams.length > 0 ? teams[0].id : null;
    
          return {
            data: {
              ...session,
              activeTeamId,
              teams: teams.map((team) => ({
                id: team.id,
                slug: team.slug,
                userId: session.userId,
                role: team.role,
              })),
            },
          };
        },
      },
    },
    
    
  2. Inspect the session data stored in Redis. The fields activeTeamId and teams are missing.

  3. Modify the code to directly update the session object:

session: {
  create: {
    before: async (session) => {
      const teams = await findAllUserTeams(drizzle, session.userId);
      const activeTeamId = teams.length > 0 ? teams[0].id : null;

      session.activeTeamId = activeTeamId;
      session.teams = teams;
    },
  },
},
  1. Inspect the session data stored in Redis again. The fields activeTeamId and teams are now correctly stored.

What version of Better Auth are you using?

1.1.1

Provide environment information

chrome

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

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

No response

Originally created by @wh5938316 on GitHub (Dec 23, 2024). Original GitHub issue: https://github.com/better-auth/better-auth/issues/993 ### Is this suited for github? - [ ] Yes, this is suited for github ### To Reproduce First, I enabled secondary storage. When using the `session.create.before` hook, returning additional session fields via the `data` property in the return value does not store those fields in Redis. However, directly modifying the `session` object works as expected. According to the [documentation](https://www.better-auth.com/docs/concepts/database#1-before-hook), session.create.before is expected to accept the returned modified session and store it in the database. However, in practice, only directly modifying the reference of the passed-in session object takes effect. This behavior is inconsistent with the documentation. Is this the intended behavior? ### Current vs. Expected behavior 1. Use the following `before` hook configuration: ```javascript session: { create: { before: async (session) => { const teams = await findAllUserTeams(drizzle, session.userId); const activeTeamId = teams.length > 0 ? teams[0].id : null; return { data: { ...session, activeTeamId, teams: teams.map((team) => ({ id: team.id, slug: team.slug, userId: session.userId, role: team.role, })), }, }; }, }, }, 2. Inspect the session data stored in Redis. The fields `activeTeamId` and `teams` are missing. 3. Modify the code to directly update the session object: ```javascript session: { create: { before: async (session) => { const teams = await findAllUserTeams(drizzle, session.userId); const activeTeamId = teams.length > 0 ? teams[0].id : null; session.activeTeamId = activeTeamId; session.teams = teams; }, }, }, ``` 4. Inspect the session data stored in Redis again. The fields `activeTeamId` and `teams` are now correctly stored. ### What version of Better Auth are you using? 1.1.1 ### Provide environment information ```bash chrome ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-15 15:09:54 -05:00
Author
Owner

@Bekacru commented on GitHub (Dec 23, 2024):

this is probably related to #994 should be fixed on latest 1.1.2

<!-- gh-comment-id:2558985882 --> @Bekacru commented on GitHub (Dec 23, 2024): this is probably related to #994 should be fixed on latest `1.1.2`
Author
Owner

@wh5938316 commented on GitHub (Dec 23, 2024):

this is probably related to #994 should be fixed on latest 1.1.2

I am using better-auth@1.1.2, but unfortunately, the issue still persists. I conducted a simple test and discovered that the problem lies in the set method of the secondary storage being executed twice when writing the session. The first execution writes the modified session, but the second execution writes the initial session, which causes the session to be overwritten.

Here’s the secondary storage configuration I am using:

secondaryStorage: {
  get: async (key) => {
    const value = await redis.get(key);
    if (!value) return null;
    return value;
  },
  set: async (key, value, ttl) => {
    console.log('ddddd', key);
    if (ttl) {
      await redis.set(key, value, 'EX', ttl);
    } else {
      await redis.set(key, value);
    }
  },
  delete: async (key) => (await redis.del(key)) as any,
},

Here’s the log output:

ddddd dC0S7Xh9vCKXxIjoWu4nE2fwdkFga7Yp
ddddd active-sessions-00000000-0000-0000-0000-000000000000
ddddd dC0S7Xh9vCKXxIjoWu4nE2fwdkFga7Yp

It appears the session is being written twice, and the second write operation overwrites the modified session with the initial session. Could you please take another look at this? Let me know if you need additional information to help debug the issue.

<!-- gh-comment-id:2559039346 --> @wh5938316 commented on GitHub (Dec 23, 2024): > this is probably related to #994 should be fixed on latest `1.1.2` I am using better-auth@1.1.2, but unfortunately, the issue still persists. I conducted a simple test and discovered that the problem lies in the set method of the secondary storage being executed twice when writing the session. The first execution writes the modified session, but the second execution writes the initial session, which causes the session to be overwritten. Here’s the secondary storage configuration I am using: ```javascript secondaryStorage: { get: async (key) => { const value = await redis.get(key); if (!value) return null; return value; }, set: async (key, value, ttl) => { console.log('ddddd', key); if (ttl) { await redis.set(key, value, 'EX', ttl); } else { await redis.set(key, value); } }, delete: async (key) => (await redis.del(key)) as any, }, ``` Here’s the log output: ``` ddddd dC0S7Xh9vCKXxIjoWu4nE2fwdkFga7Yp ddddd active-sessions-00000000-0000-0000-0000-000000000000 ddddd dC0S7Xh9vCKXxIjoWu4nE2fwdkFga7Yp ``` It appears the session is being written twice, and the second write operation overwrites the modified session with the initial session. Could you please take another look at this? Let me know if you need additional information to help debug the issue.
Author
Owner

@wh5938316 commented on GitHub (Dec 23, 2024):

One more thing to add: the issue of writing the session twice already existed in version 1.1.1

<!-- gh-comment-id:2559043982 --> @wh5938316 commented on GitHub (Dec 23, 2024): One more thing to add: the issue of writing the session twice already existed in version 1.1.1
Author
Owner

@Bekacru commented on GitHub (Dec 23, 2024):

check 1.1.3-beta.1 and confirm me if it's fixed

<!-- gh-comment-id:2559114428 --> @Bekacru commented on GitHub (Dec 23, 2024): check `1.1.3-beta.1` and confirm me if it's fixed
Author
Owner

@wh5938316 commented on GitHub (Dec 23, 2024):

check 1.1.3-beta.1 and confirm me if it's fixed

Thank you for your efforts!

After upgrading to 1.1.3-beta.1, the value of the session token stored in Redis is now correct.

However, I noticed that the session is still being written twice: once before the active-session written and once after.

Is this the expected behavior?

<!-- gh-comment-id:2559134108 --> @wh5938316 commented on GitHub (Dec 23, 2024): > check `1.1.3-beta.1` and confirm me if it's fixed Thank you for your efforts! After upgrading to `1.1.3-beta.1`, the value of the session token stored in Redis is now correct. However, I noticed that the session is still being written twice: once before the active-session written and once after. Is this the expected behavior?
Author
Owner

@Bekacru commented on GitHub (Dec 23, 2024):

what plugins are you using?

<!-- gh-comment-id:2559222997 --> @Bekacru commented on GitHub (Dec 23, 2024): what plugins are you using?
Author
Owner

@wh5938316 commented on GitHub (Dec 23, 2024):

what plugins are you using?

The plugins I have enabled are admin, anonymous, organization, jwt, and bearer.

I tried commenting out all the plugins, but secondaryStorage.set still writes the session twice during login.

Here’s the secondary storage configuration I am using:

secondaryStorage: {
  get: async (key) => {
    const value = await redis.get(key);
    if (!value) return null;
    return value;
  },
  set: async (key, value, ttl) => {
    console.log('ddddd', key);
    if (ttl) {
      await redis.set(key, value, 'EX', ttl);
    } else {
      await redis.set(key, value);
    }
  },
  delete: async (key) => (await redis.del(key)) as any,
},
console.log(1111);
const response = await this.auth.api.signInEmail({
  request: req,
  body: {
    email: _.get(data, 'email'),
    password: _.get(data, 'password'),
    dotRememberMe: _.get(data, 'remember_me', false),
    callbackUrl: _.get(data, 'callback_url'),
  },
  asResponse: true,
});
console.log(2222);

Here’s the log output:

1111
ddddd UNApfCRh8Igui9uPFBoMv1kHg90oKrGE
ddddd active-sessions-00000000-0000-0000-0000-000000000000
ddddd UNApfCRh8Igui9uPFBoMv1kHg90oKrGE
2222
<!-- gh-comment-id:2559268807 --> @wh5938316 commented on GitHub (Dec 23, 2024): > what plugins are you using? The plugins I have enabled are `admin`, `anonymous`, `organization`, `jwt`, and `bearer`. I tried commenting out all the plugins, but secondaryStorage.set still writes the session twice during login. Here’s the secondary storage configuration I am using: ```javascript secondaryStorage: { get: async (key) => { const value = await redis.get(key); if (!value) return null; return value; }, set: async (key, value, ttl) => { console.log('ddddd', key); if (ttl) { await redis.set(key, value, 'EX', ttl); } else { await redis.set(key, value); } }, delete: async (key) => (await redis.del(key)) as any, }, ``` ```javascript console.log(1111); const response = await this.auth.api.signInEmail({ request: req, body: { email: _.get(data, 'email'), password: _.get(data, 'password'), dotRememberMe: _.get(data, 'remember_me', false), callbackUrl: _.get(data, 'callback_url'), }, asResponse: true, }); console.log(2222); ``` Here’s the log output: ``` 1111 ddddd UNApfCRh8Igui9uPFBoMv1kHg90oKrGE ddddd active-sessions-00000000-0000-0000-0000-000000000000 ddddd UNApfCRh8Igui9uPFBoMv1kHg90oKrGE 2222 ```
Author
Owner

@Bekacru commented on GitHub (Dec 23, 2024):

Yeah this was a bug, should be fixed on 1.1.3-beta.2

<!-- gh-comment-id:2559338227 --> @Bekacru commented on GitHub (Dec 23, 2024): Yeah this was a bug, should be fixed on `1.1.3-beta.2`
Author
Owner

@wh5938316 commented on GitHub (Dec 23, 2024):

Yeah this was a bug, should be fixed on 1.1.3-beta.2

After upgrading to 1.1.3-beta.2, the issue has been resolved. Thank you again for your efforts!

<!-- gh-comment-id:2559366648 --> @wh5938316 commented on GitHub (Dec 23, 2024): > Yeah this was a bug, should be fixed on `1.1.3-beta.2` After upgrading to 1.1.3-beta.2, the issue has been resolved. Thank you again for your efforts!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#17171