[GH-ISSUE #4767] The data in databaseHooks.session.update.before is limited compared to the .create.before version #27378

Closed
opened 2026-04-17 18:22:37 -05:00 by GiteaMirror · 11 comments
Owner

Originally created by @SkepticMystic on GitHub (Sep 19, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/4767

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Add the following databaseHooks:
      databaseHooks: {
        session: {
          create: {
            before: async (session, ctx) => {
              console.log(session, ctx, "session.create.before");
            },
          },

          update: {
            before: async (session, ctx) => {
              console.log(session, ctx, "session.update.before");
            },
          },
        },
      },
  1. Signin to create a new session, view logs
  2. Do something to update the current session, like authClient.organization.setActive, view logs

Current vs. Expected behavior

The data available on the session object in the create hook has far more fields available. The update hook only has activeOrganizationId for me

What version of Better Auth are you using?

1.3.12

System info

Nothing gets output when I run this...

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

Backend

Additional context

Initial Discord support thread: https://discord.com/channels/1288403910284935179/1415281222304661534

Originally created by @SkepticMystic on GitHub (Sep 19, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/4767 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Add the following databaseHooks: ```ts databaseHooks: { session: { create: { before: async (session, ctx) => { console.log(session, ctx, "session.create.before"); }, }, update: { before: async (session, ctx) => { console.log(session, ctx, "session.update.before"); }, }, }, }, ``` 2. Signin to create a new session, view logs 3. Do something to _update_ the current session, like `authClient.organization.setActive`, view logs ### Current vs. Expected behavior The data available on the `session` object in the `create` hook has far more fields available. The `update` hook only has `activeOrganizationId` for me ### What version of Better Auth are you using? 1.3.12 ### System info ```bash Nothing gets output when I run this... ``` ### Which area(s) are affected? (Select all that apply) Backend ### Additional context Initial Discord support thread: https://discord.com/channels/1288403910284935179/1415281222304661534
GiteaMirror added the lockedenhancement labels 2026-04-17 18:22:37 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Sep 19, 2025):

This is expected behavior in Better Auth. The session.create.before hook receives the full session object because it's constructing a new session, while session.update.before only receives the fields being updated (like activeOrganizationId)—not the full session record. This is by design and matches how many ORMs and hook systems work: before-update hooks only get the partial update payload, not the entire record snapshot, unless you explicitly load it yourself.

If you need more context in session.update.before, you can manually fetch the full session from your database using the session token or other identifiers available in the hook context. There’s no built-in enrichment for the update hook, so this manual step is necessary if you need the full session data for your logic. This pattern is consistent across the codebase and not considered a bug (source, types).

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:3311988546 --> @dosubot[bot] commented on GitHub (Sep 19, 2025): <!-- Answer --> This is expected behavior in Better Auth. The `session.create.before` hook receives the full session object because it's constructing a new session, while `session.update.before` only receives the fields being updated (like `activeOrganizationId`)—not the full session record. This is by design and matches how many ORMs and hook systems work: before-update hooks only get the partial update payload, not the entire record snapshot, unless you explicitly load it yourself. If you need more context in `session.update.before`, you can manually fetch the full session from your database using the session token or other identifiers available in the hook context. There’s no built-in enrichment for the update hook, so this manual step is necessary if you need the full session data for your logic. This pattern is consistent across the codebase and not considered a bug ([source](https://github.com/better-auth/better-auth/blob/57510365a393bca2f6a37e50c43571651b121978/packages/better-auth/src/db/internal-adapter.ts), [types](https://github.com/better-auth/better-auth/blob/57510365a393bca2f6a37e50c43571651b121978/packages/better-auth/src/types/options.ts)). <!-- 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/c428fe34-df3a-427a-b90e-b1dd3710c98c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/c428fe34-df3a-427a-b90e-b1dd3710c98c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/c428fe34-df3a-427a-b90e-b1dd3710c98c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/c428fe34-df3a-427a-b90e-b1dd3710c98c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/c428fe34-df3a-427a-b90e-b1dd3710c98c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/c428fe34-df3a-427a-b90e-b1dd3710c98c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/c428fe34-df3a-427a-b90e-b1dd3710c98c?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/4767)
Author
Owner

@SkepticMystic commented on GitHub (Sep 19, 2025):

Looking at this code, I understand why. It's a patch, not a full update.

The broader problem in my use case is that I need other info about the current session, like userId. But when setting active org, the only info available in the session patch is the new orgId. So I can't tell which user is being update (in the context of the hook).
I would usually use the escape hatch of ctx in the hook, but it's undefined in this case

<!-- gh-comment-id:3312001447 --> @SkepticMystic commented on GitHub (Sep 19, 2025): Looking at [this code](https://github.com/better-auth/better-auth/blob/a208c0989455cba0843cd34679618c457fe05c62/packages/better-auth/src/db/internal-adapter.ts#L480), I understand why. It's a patch, not a full update. The broader problem in my use case is that I need other info about the current session, like userId. But when setting active org, the only info available in the session _patch_ is the new orgId. So I can't tell which user is being update (in the context of the hook). I would usually use the escape hatch of `ctx` in the hook, but it's `undefined` in this case
Author
Owner
<!-- gh-comment-id:3312003659 --> @SkepticMystic commented on GitHub (Sep 19, 2025): Indeed, the org plugin doesn't pass `ctx`: https://github.com/better-auth/better-auth/blob/a208c0989455cba0843cd34679618c457fe05c62/packages/better-auth/src/plugins/organization/adapter.ts#L378
Author
Owner

@SkepticMystic commented on GitHub (Sep 19, 2025):

I see two possible solutions for my use case:

<!-- gh-comment-id:3312024290 --> @SkepticMystic commented on GitHub (Sep 19, 2025): I see two possible solutions for my use case: - The org plugin can pass `ctx` into the updateSession call - The internal adapter could pass the sessionToken with the `session` patch, which I could use to lookup the full object: https://github.com/better-auth/better-auth/blob/a208c0989455cba0843cd34679618c457fe05c62/packages/better-auth/src/db/internal-adapter.ts#L480
Author
Owner

@ping-maxwell commented on GitHub (Sep 19, 2025):

The org plugin can pass ctx into the updateSession call

We should do this

<!-- gh-comment-id:3312025846 --> @ping-maxwell commented on GitHub (Sep 19, 2025): > The org plugin can pass ctx into the updateSession call We should do this
Author
Owner

@ping-maxwell commented on GitHub (Sep 19, 2025):

Do you want to open a PR? Otherwise I can

<!-- gh-comment-id:3312026971 --> @ping-maxwell commented on GitHub (Sep 19, 2025): Do you want to open a PR? Otherwise I can
Author
Owner

@SkepticMystic commented on GitHub (Sep 19, 2025):

Please will you do it, this is the furthest I've looked at this codebase before 😄

<!-- gh-comment-id:3312032016 --> @SkepticMystic commented on GitHub (Sep 19, 2025): Please will you do it, this is the furthest I've looked at this codebase before 😄
Author
Owner

@ping-maxwell commented on GitHub (Sep 19, 2025):

@SkepticMystic I think that it's intentional, there is no context of the session before hand so the before only returns what is about to be updated on a given session.

The reason why create.before is filled is because in order to create a session you would need to fill all the details of a session obj in the first place

<!-- gh-comment-id:3312176478 --> @ping-maxwell commented on GitHub (Sep 19, 2025): @SkepticMystic I think that it's intentional, there is no context of the session before hand so the `before` only returns what is *about* to be updated on a given session. The reason why `create.before` is filled is because in order to create a session you would need to fill all the details of a session obj in the first place
Author
Owner

@SkepticMystic commented on GitHub (Sep 19, 2025):

It makes sense that the session arg is partial, but can't the GenericEndpointContext be passed in? So that I can see which user is updating their session

<!-- gh-comment-id:3312182958 --> @SkepticMystic commented on GitHub (Sep 19, 2025): It makes sense that the `session` arg is partial, but can't the `GenericEndpointContext` be passed in? So that I can see which user is updating their session
Author
Owner

@SkepticMystic commented on GitHub (Sep 19, 2025):

Or the sessionToken could be set on the session object passed into the hook. It's used to find the session to update, so it doesn't matter if the db also sets it on the session again.

session: Partial<Session> & { token: string } & Record<string, unknown>

<!-- gh-comment-id:3312205872 --> @SkepticMystic commented on GitHub (Sep 19, 2025): Or the `sessionToken` could be set on the `session` object passed into the hook. It's used to _find_ the session to update, so it doesn't matter if the db also sets it on the session again. `session: Partial<Session> & { token: string } & Record<string, unknown>`
Author
Owner

@SkepticMystic commented on GitHub (Sep 19, 2025):

Possible XY problem.

  • When a user signsin, I hook into session.create.before and fetch the first org they're a member of, then set the activeOrganizationId on the session. I also set the memberId and memberRole on the session, for quick access.
  • When calling authClient.organization.setActive, the org plugin automatically handles the activeOrganizationId, as we've seen from the linked code. But the memberId and memberRole fields don't get updated, cause they're custom fields I've added.
  • One solution would be to hook into session.update.before, but it's clear now that not enough data is available to fetch the member
<!-- gh-comment-id:3312316460 --> @SkepticMystic commented on GitHub (Sep 19, 2025): Possible XY problem. - When a user signsin, I hook into `session.create.before` and fetch the first org they're a member of, then set the `activeOrganizationId` on the session. I also set the `memberId` and `memberRole` on the session, for quick access. - When calling `authClient.organization.setActive`, the org plugin automatically handles the `activeOrganizationId`, as we've seen from the linked code. But the `memberId` and `memberRole` fields don't get updated, cause they're custom fields I've added. - One solution would be to hook into `session.update.before`, but it's clear now that not enough data is available to fetch the member
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#27378