getActiveOrganization implementation #1058

Closed
opened 2026-03-13 08:20:45 -05:00 by GiteaMirror · 14 comments
Owner

Originally created by @rinarakaki on GitHub (Apr 16, 2025).

Originally assigned to: @ping-maxwell on GitHub.

https://www.better-auth.com/docs/plugins/organization#set-active-organization

I could neither find the implementation or get the idea.
If authClient.organization.setActive is all about the client side, for example storing active organization info on cookie or local storage, there's no way or need to get active org on the server side.
If setting active organization is done on the server side, there can/should be an official implementation, I think.

Originally created by @rinarakaki on GitHub (Apr 16, 2025). Originally assigned to: @ping-maxwell on GitHub. https://www.better-auth.com/docs/plugins/organization#set-active-organization I could neither find the implementation or get the idea. If `authClient.organization.setActive` is all about the client side, for example storing active organization info on cookie or local storage, there's no way or need to get active org on the server side. If setting active organization is done on the server side, there can/should be an official implementation, I think.
GiteaMirror added the enhancementwontfix labels 2026-03-13 08:20:45 -05:00
Author
Owner

@SNRSE commented on GitHub (Apr 16, 2025):

Hey, I know this might not be what you want, but here is how I do it currently with my Express / Node.js server :
I have an "auth middleware" I use in front of any routes I need info about the user ( but you can also do it without a middleware)
Here is my Middleware :

export default async function sessionMiddleware(req: Request, res: Response, next: NextFunction) {
    const sessionResponse = await auth.api.getSession({
        headers: fromNodeHeaders(req.headers),
    });
    const session = sessionResponse?.session;
    // Add the session to the request object
    req.session = session;
    if (!session?.userId) {
        res.status(401).json({ error: "Unauthorized" });
        return;
    } else {
        next();
    }
}

And here is how I get the organisation, then after that :

const activeOrganisation=  req.session.activeOrganizationId;

If you want to do it all in one

 const authSession = await auth.api.getSession({
        headers: fromNodeHeaders(req.headers),
    });
const activeOrganisation=  authSession.activeOrganizationId;


Hope this helps a bit.

@SNRSE commented on GitHub (Apr 16, 2025): Hey, I know this might not be what you want, but here is how I do it currently with my Express / Node.js server : I have an "auth middleware" I use in front of any routes I need info about the user ( but you can also do it without a middleware) Here is my Middleware : ```typescript export default async function sessionMiddleware(req: Request, res: Response, next: NextFunction) { const sessionResponse = await auth.api.getSession({ headers: fromNodeHeaders(req.headers), }); const session = sessionResponse?.session; // Add the session to the request object req.session = session; if (!session?.userId) { res.status(401).json({ error: "Unauthorized" }); return; } else { next(); } } ``` And here is how I get the organisation, then after that : ```typescript const activeOrganisation= req.session.activeOrganizationId; ``` If you want to do it all in one ```typescript const authSession = await auth.api.getSession({ headers: fromNodeHeaders(req.headers), }); const activeOrganisation= authSession.activeOrganizationId; ``` Hope this helps a bit.
Author
Owner

@ping-maxwell commented on GitHub (Apr 20, 2025):

You can get the user's session, which includes active_organization_id.

We won't have an "official" implementation of this since there basically already is.
Just call getSession, and there you have active_organization_id.

@ping-maxwell commented on GitHub (Apr 20, 2025): You can get the user's session, which includes `active_organization_id`. We won't have an "official" implementation of this since there basically already is. Just call getSession, and there you have `active_organization_id`.
Author
Owner

@widavies commented on GitHub (May 8, 2025):

@ping-maxwell Is there any chance we could get a activeOrganizationSlug too?

My use case:

  1. User navigates to mydomain.com
  2. I redirect them to their active organization mydomain.com/active-slug

Right now this requires getFullOrganization to resolve the slug from activeOrganizationId. As this is somewhat of a hot path, would be nice to skip the database call here.

@widavies commented on GitHub (May 8, 2025): @ping-maxwell Is there any chance we could get a `activeOrganizationSlug` too? My use case: 1) User navigates to `mydomain.com` 2) I redirect them to their active organization `mydomain.com/active-slug` Right now this requires `getFullOrganization` to resolve the slug from `activeOrganizationId`. As this is somewhat of a hot path, would be nice to skip the database call here.
Author
Owner

@ping-maxwell commented on GitHub (May 8, 2025):

@ping-maxwell Is there any chance we could get a activeOrganizationSlug too?

My use case:

  1. User navigates to mydomain.com
  2. I redirect them to their active organization mydomain.com/active-slug

Right now this requires getFullOrganization to resolve the slug from activeOrganizationId. As this is somewhat of a hot path, would be nice to skip the database call here.

You'll have to query the DB, or call getFullOrganization. This isn't the same as the activeOrganizationId where it's part of the session

@ping-maxwell commented on GitHub (May 8, 2025): > [@ping-maxwell](https://github.com/ping-maxwell) Is there any chance we could get a `activeOrganizationSlug` too? > > My use case: > > 1. User navigates to `mydomain.com` > 2. I redirect them to their active organization `mydomain.com/active-slug` > > Right now this requires `getFullOrganization` to resolve the slug from `activeOrganizationId`. As this is somewhat of a hot path, would be nice to skip the database call here. You'll have to query the DB, or call getFullOrganization. This isn't the same as the activeOrganizationId where it's part of the session
Author
Owner

@simon-barker-redbrain commented on GitHub (May 12, 2025):

I think I'm missing something here as well. To populate activeOrganizationId in the session we need to manually set it. So the docs suggest this:

export const auth = betterAuth({
  databaseHooks: {
      session: {
          create: {
              before: async(session)=>{
                  const organization = await getActiveOrganization(session.userId)
                  return {
                    data: {
                      ...session,
                      activeOrganizationId: organization.id
                    }
                  }
              }
          }
      }
  }
})

@ping-maxwell your suggestion above is to call getFullOrganization but that call requires query: {organizationId: "ORG_ID"} to work ... so we seem to be in a circular dependency pickle.

Is the envisaged contents of getActiveOrganization a manual call to the database to join user and organization ? If so I agree with the initial poster @rinarakaki that this should be implemented by the package, or the docs improved.

Some clarification would be great, thanks.

@simon-barker-redbrain commented on GitHub (May 12, 2025): I think I'm missing something here as well. To populate `activeOrganizationId` in the session we need to manually set it. So the docs suggest this: ``` export const auth = betterAuth({ databaseHooks: { session: { create: { before: async(session)=>{ const organization = await getActiveOrganization(session.userId) return { data: { ...session, activeOrganizationId: organization.id } } } } } } }) ``` @ping-maxwell your suggestion above is to call `getFullOrganization` but that call requires `query: {organizationId: "ORG_ID"}` to work ... so we seem to be in a circular dependency pickle. Is the envisaged contents of `getActiveOrganization` a manual call to the database to join `user` and `organization` ? If so I agree with the initial poster @rinarakaki that this should be implemented by the package, or the docs improved. Some clarification would be great, thanks.
Author
Owner

@TheKeyB commented on GitHub (May 19, 2025):

I would like to understand what exactly is taking place inside "getActiveOrganization". Is it just a function that queries the db to get the first organization that the user is a member of?

@TheKeyB commented on GitHub (May 19, 2025): I would like to understand what exactly is taking place inside "getActiveOrganization". Is it just a function that queries the db to get the first organization that the user is a member of?
Author
Owner

@radosek commented on GitHub (Jun 19, 2025):

@TheKeyB seems like it is.

@radosek commented on GitHub (Jun 19, 2025): @TheKeyB seems like it is.
Author
Owner

@ping-maxwell commented on GitHub (Jun 20, 2025):

Here's what I recommend, make a custom function (eg getActiveOrganization). This is a custom function which does a database call to query for whatever data you need. In theory you only need the user id to figure out the active organization and then find info about that org.

@ping-maxwell commented on GitHub (Jun 20, 2025): Here's what I recommend, make a custom function (eg `getActiveOrganization`). This is a custom function which does a database call to query for whatever data you need. In theory you only need the user id to figure out the active organization and then find info about that org.
Author
Owner

@belfed commented on GitHub (Jun 21, 2025):

Here's what I recommend, make a custom function (eg getActiveOrganization). This is a custom function which does a database call to query for whatever data you need. In theory you only need the user id to figure out the active organization and then find info about that org.

I'm sorry if this is a banal question, but as far as I can see the only entity that holds the id of the active organization is the session (session.activeOrganizationId), so how do I look for the active organization inside a session that is being created in this moment? Shouldn't it be some account-related default?

@belfed commented on GitHub (Jun 21, 2025): > Here's what I recommend, make a custom function (eg `getActiveOrganization`). This is a custom function which does a database call to query for whatever data you need. In theory you only need the user id to figure out the active organization and then find info about that org. I'm sorry if this is a banal question, but as far as I can see the only entity that holds the id of the active organization is the session (`session.activeOrganizationId`), so how do I look for the active organization inside a session that is being created in this moment? Shouldn't it be some account-related default?
Author
Owner

@radosek commented on GitHub (Jun 21, 2025):

@belfed something like this. You have to look in the database.

databaseHooks: {
  session: {
    create: {
      before: async (session) => {
        const member = await db
          .select()
          .from(members)
          .where(eq(members.userId, session.id ?? ""))
          .limit(1)
          .get();

        return {
          data: {
            ...session,
            ...(member?.organizationId && { activeOrganizationId: member?.organizationId }),
          },
        };
      },
    },
  },
},
@radosek commented on GitHub (Jun 21, 2025): @belfed something like this. You have to look in the database. ```ts databaseHooks: { session: { create: { before: async (session) => { const member = await db .select() .from(members) .where(eq(members.userId, session.id ?? "")) .limit(1) .get(); return { data: { ...session, ...(member?.organizationId && { activeOrganizationId: member?.organizationId }), }, }; }, }, }, }, ```
Author
Owner

@belfed commented on GitHub (Jun 23, 2025):

@belfed something like this. You have to look in the database.

databaseHooks: {
session: {
create: {
before: async (session) => {
const member = await db
.select()
.from(members)
.where(eq(members.userId, session.id ?? ""))
.limit(1)
.get();

    return {
      data: {
        ...session,
        ...(member?.organizationId && { activeOrganizationId: member?.organizationId }),
      },
    };
  },
},

},
},

Thanks for the suggestions, but I managed to just set the active organization:

  • after the sign-in: by looking for the first organization related to the user.
  • after the sign-up: the user is redirected to the "Create new organization" page and, when done, the organization itself is set as active.
@belfed commented on GitHub (Jun 23, 2025): > [@belfed](https://github.com/belfed) something like this. You have to look in the database. > > databaseHooks: { > session: { > create: { > before: async (session) => { > const member = await db > .select() > .from(members) > .where(eq(members.userId, session.id ?? "")) > .limit(1) > .get(); > > return { > data: { > ...session, > ...(member?.organizationId && { activeOrganizationId: member?.organizationId }), > }, > }; > }, > }, > }, > }, Thanks for the suggestions, but I managed to just set the active organization: - after the sign-in: by looking for the first organization related to the user. - after the sign-up: the user is redirected to the "Create new organization" page and, when done, the organization itself is set as active.
Author
Owner

@0ni-x4 commented on GitHub (Oct 2, 2025):

Here's what I recommend, make a custom function (eg getActiveOrganization). This is a custom function which does a database call to query for whatever data you need. In theory you only need the user id to figure out the active organization and then find info about that org.

Right now, switching active organizations requires a DB call to resolve metadata (slug, name, etc.), since only activeOrganizationId is stored in the session.

From a performance perspective, this adds latency for every org switch. Wouldn’t it make more sense for the session to include not just activeOrganizationId, but also a lightweight array of all organizations the user belongs to (id, slug, name, maybe role)? That way, switching organizations could be handled entirely client-side without hitting the DB.

The trade-off, of course, is larger session payloads but for most apps the number of orgs per user is low enough that the impact would be minimal compared to the benefit of eliminating unnecessary DB calls.

@0ni-x4 commented on GitHub (Oct 2, 2025): > Here's what I recommend, make a custom function (eg `getActiveOrganization`). This is a custom function which does a database call to query for whatever data you need. In theory you only need the user id to figure out the active organization and then find info about that org. Right now, switching active organizations requires a DB call to resolve metadata (slug, name, etc.), since only activeOrganizationId is stored in the session. From a performance perspective, this adds latency for every org switch. Wouldn’t it make more sense for the session to include not just activeOrganizationId, but also a lightweight array of all organizations the user belongs to (id, slug, name, maybe role)? That way, switching organizations could be handled entirely client-side without hitting the DB. The trade-off, of course, is larger session payloads but for most apps the number of orgs per user is low enough that the impact would be minimal compared to the benefit of eliminating unnecessary DB calls.
Author
Owner

@ping-maxwell commented on GitHub (Oct 2, 2025):

From a performance perspective, this adds latency for every org switch

Yeah. I personally recommend making tracking of the "active organization" on the client side so that you don't need to hit the server (and thus the DB too).
Our activeOrganizationId is designed as more of a convenience, but most cases it makes more sense to handle tracking of the active org on the client. In every org endpoint you should be able to pass an organizationId which would overwrite the logic to looking for the user's activeOrganizationId.

but also a lightweight array of all organizations the user belongs to (id, slug, name, maybe role)? That way, switching organizations could be handled entirely client-side without hitting the DB.

I don't think this is a good idea. It's better to query all orgs when it's necessary. In your case if you really want an array of orgs in session then I recommend looking into the custom session plugin.

@ping-maxwell commented on GitHub (Oct 2, 2025): > From a performance perspective, this adds latency for every org switch Yeah. I personally recommend making tracking of the "active organization" on the client side so that you don't need to hit the server (and thus the DB too). Our `activeOrganizationId` is designed as more of a convenience, but most cases it makes more sense to handle tracking of the active org on the client. In every org endpoint you should be able to pass an `organizationId` which would overwrite the logic to looking for the user's `activeOrganizationId`. > but also a lightweight array of all organizations the user belongs to (id, slug, name, maybe role)? That way, switching organizations could be handled entirely client-side without hitting the DB. I don't think this is a good idea. It's better to query all orgs when it's necessary. In your case if you really want an array of orgs in session then I recommend looking into the [custom session](https://www.better-auth.com/docs/concepts/session-management#customizing-session-response) plugin.
Author
Owner

@widavies commented on GitHub (Oct 2, 2025):

For reference, I solved this by doing what @ping-maxwell suggested and customizing the session claims. I use Convex which uses JWTs for auth, so I just use the definePayload callback on the JWT config to inject the activeOrganizationSlug.

@widavies commented on GitHub (Oct 2, 2025): For reference, I solved this by doing what @ping-maxwell suggested and customizing the session claims. I use Convex which uses JWTs for auth, so I just use the `definePayload` callback on the JWT config to inject the activeOrganizationSlug.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1058