[GH-ISSUE #9070] databaseHooks.session.create.before cannot set activeOrganizationId on first signup #19895

Open
opened 2026-04-15 19:15:25 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @marbemac on GitHub (Apr 9, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/9070

Is this suited for github?

  • Yes, this is suited for github

Reproduction

  1. Configure databaseHooks.session.create.before to look up the user's org membership and set activeOrganizationId on the session — as recommended in the organization plugin docs
  2. Have a brand new user sign up (social or email — doesn't matter)
  3. Observe that the session is created without activeOrganizationId because the organization member row does not exist yet when the before hook fires
  4. Have the same user sign in again — now it works, because the member row was persisted during step 2

Why it happens

During a first-time signup, the organization plugin creates the member row after the session is created. So when session.create.before fires, it queries for the member row to determine activeOrganizationId, but that row doesn't exist yet. The query returns null, and the session is written without an active org.

On subsequent sign-ins the member row already exists from the original signup, so the hook finds it and sets activeOrganizationId correctly.

Current vs. Expected behavior

Current: First-time signup sessions have activeOrganizationId: null because the session.create.before hook fires before the organization plugin has created the member row. Subsequent sign-ins work fine.

Expected: The documented pattern of using databaseHooks.session.create.before to set activeOrganizationId should work for first-time signups, not just returning users. Possible solutions:

  1. The organization plugin could create the member row before the session is created, so the before hook can find it
  2. The organization plugin could handle setting activeOrganizationId on the session internally, without requiring userland hooks
  3. A new hook phase that runs after all plugin side-effects but before the response is sent

What version of Better Auth are you using?

v1.6.x (worked prior to 1.6)

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

Backend

Auth config (if applicable)

databaseHooks: {
  session: {
    create: {
      before: async (session) => {
        const member = await db.findFirst("member", {
          where: [{ field: "userId", value: session.userId }],
        });

        return {
          data: {
            ...session,
            activeOrganizationId: member?.organizationId ?? null,
          },
        };
      },
    },
  },
},

Additional context

  • The organization plugin docs recommend using databaseHooks for this exact pattern, but it doesn't work for new signups because the member row is created after the session
  • This is an ordering issue within the signup flow: session creation (and its hooks) happens before the organization plugin creates the membership
Originally created by @marbemac on GitHub (Apr 9, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/9070 ### Is this suited for github? - [x] Yes, this is suited for github ## Reproduction 1. Configure `databaseHooks.session.create.before` to look up the user's org membership and set `activeOrganizationId` on the session — as recommended in the [organization plugin docs](https://www.better-auth.com/docs/plugins/organization#extracting-active-organization-id-from-session) 2. Have a **brand new user** sign up (social or email — doesn't matter) 3. Observe that the session is created **without** `activeOrganizationId` because the organization member row does not exist yet when the `before` hook fires 4. Have the **same user** sign in again — now it works, because the member row was persisted during step 2 ### Why it happens During a first-time signup, the organization plugin creates the member row **after** the session is created. So when `session.create.before` fires, it queries for the member row to determine `activeOrganizationId`, but that row doesn't exist yet. The query returns `null`, and the session is written without an active org. On subsequent sign-ins the member row already exists from the original signup, so the hook finds it and sets `activeOrganizationId` correctly. ## Current vs. Expected behavior **Current:** First-time signup sessions have `activeOrganizationId: null` because the `session.create.before` hook fires before the organization plugin has created the member row. Subsequent sign-ins work fine. **Expected:** The documented pattern of using `databaseHooks.session.create.before` to set `activeOrganizationId` should work for first-time signups, not just returning users. Possible solutions: 1. The organization plugin could create the member row **before** the session is created, so the `before` hook can find it 2. The organization plugin could handle setting `activeOrganizationId` on the session internally, without requiring userland hooks 3. A new hook phase that runs after all plugin side-effects but before the response is sent ### What version of Better Auth are you using? `v1.6.x` (worked prior to 1.6) ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript databaseHooks: { session: { create: { before: async (session) => { const member = await db.findFirst("member", { where: [{ field: "userId", value: session.userId }], }); return { data: { ...session, activeOrganizationId: member?.organizationId ?? null, }, }; }, }, }, }, ``` ### Additional context - The [organization plugin docs](https://www.better-auth.com/docs/plugins/organization#extracting-active-organization-id-from-session) recommend using `databaseHooks` for this exact pattern, but it doesn't work for new signups because the member row is created after the session - This is an ordering issue within the signup flow: session creation (and its hooks) happens before the organization plugin creates the membership
GiteaMirror added the database label 2026-04-15 19:15:25 -05:00
Author
Owner

@sicarius97 commented on GitHub (Apr 9, 2026):

@marbemac The docs recommend setting the active organization id before creating the session, not after creating the session. I believe without additional configuration that the active organization inside the session isn't mutable but can be set on the client side, that way a user with multiple organizations can have a different active organization per tab. I set it using the session -> create -> before hook and it works as intended for your use case

<!-- gh-comment-id:4216470103 --> @sicarius97 commented on GitHub (Apr 9, 2026): @marbemac The docs recommend setting the active organization id before creating the session, not after creating the session. I believe without additional configuration that the active organization inside the session isn't mutable but can be set on the client side, that way a user with multiple organizations can have a different active organization per tab. I set it using the session -> create -> before hook and it works as intended for your use case
Author
Owner

@marbemac commented on GitHub (Apr 9, 2026):

Ah sorry I messed up the description! Re-wrote with clearer description of the specific issue.

<!-- gh-comment-id:4216547285 --> @marbemac commented on GitHub (Apr 9, 2026): Ah sorry I messed up the description! Re-wrote with clearer description of the specific issue.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19895