diff --git a/demo/nextjs/lib/auth-client.ts b/demo/nextjs/lib/auth-client.ts
index 2c73ce343c..2be85bc8af 100644
--- a/demo/nextjs/lib/auth-client.ts
+++ b/demo/nextjs/lib/auth-client.ts
@@ -56,4 +56,6 @@ export const {
organization,
useListOrganizations,
useActiveOrganization,
+ useActiveMember,
+ useActiveMemberRole,
} = client;
diff --git a/docs/content/docs/plugins/organization.mdx b/docs/content/docs/plugins/organization.mdx
index e2cad6e46a..78e3186c17 100644
--- a/docs/content/docs/plugins/organization.mdx
+++ b/docs/content/docs/plugins/organization.mdx
@@ -1162,6 +1162,21 @@ To get the current member of the active organization you can use the `organizati
```
+### Get Active Member Role
+To get the current role member of the active organization you can use the `organization.getActiveMemberRole` function. This function will return the user's member role in their active organization.
+
+
+ ```ts
+ type getActiveMemberRole = {
+ }
+ ```
+
+
### Add Member
If you want to add a member directly to an organization without sending an invitation, you can use the `addMember` function which can only be invoked on the server.
diff --git a/packages/better-auth/src/plugins/organization/client.ts b/packages/better-auth/src/plugins/organization/client.ts
index 6bd92bc7c4..7ecd3fb890 100644
--- a/packages/better-auth/src/plugins/organization/client.ts
+++ b/packages/better-auth/src/plugins/organization/client.ts
@@ -64,6 +64,7 @@ export const organizationClient = (
const $listOrg = atom(false);
const $activeOrgSignal = atom(false);
const $activeMemberSignal = atom(false);
+ const $activeMemberRoleSignal = atom(false);
type DefaultStatements = typeof defaultStatements;
type Statements = CO["ac"] extends AccessControl
@@ -204,13 +205,24 @@ export const organizationClient = (
},
);
+ const activeMemberRole = useAuthQuery<{ role: string }>(
+ [$activeMemberRoleSignal],
+ "/organization/get-active-member-role",
+ $fetch,
+ {
+ method: "GET",
+ },
+ );
+
return {
$listOrg,
$activeOrgSignal,
$activeMemberSignal,
+ $activeMemberRoleSignal,
activeOrganization,
listOrganizations,
activeMember,
+ activeMemberRole,
};
},
pathMethods: {
@@ -246,6 +258,12 @@ export const organizationClient = (
},
signal: "$activeMemberSignal",
},
+ {
+ matcher(path) {
+ return path.includes("/organization/update-member-role");
+ },
+ signal: "$activeMemberRoleSignal",
+ },
],
} satisfies BetterAuthClientPlugin;
};
diff --git a/packages/better-auth/src/plugins/organization/organization.ts b/packages/better-auth/src/plugins/organization/organization.ts
index ab38f691ac..400aeb8432 100644
--- a/packages/better-auth/src/plugins/organization/organization.ts
+++ b/packages/better-auth/src/plugins/organization/organization.ts
@@ -25,6 +25,7 @@ import {
listMembers,
removeMember,
updateMemberRole,
+ getActiveMemberRole,
} from "./routes/crud-members";
import {
checkOrganizationSlug,
@@ -405,6 +406,22 @@ export const organization = (options?: O) => {
* `authClient.organization.listMembers`
*/
listMembers: listMembers(options as O),
+ /**
+ * ### Endpoint
+ *
+ * GET `/organization/get-active-member-role`
+ *
+ * ### API Methods
+ *
+ * **server:**
+ * `auth.api.getActiveMemberRole`
+ *
+ * **client:**
+ * `authClient.organization.getActiveMemberRole`
+ *
+ * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/organization#api-method-organization-get-active-member-role)
+ */
+ getActiveMemberRole: getActiveMemberRole(options as O),
};
const teamSupport = options?.teams?.enabled;
const teamEndpoints = {
diff --git a/packages/better-auth/src/plugins/organization/routes/crud-members.test.ts b/packages/better-auth/src/plugins/organization/routes/crud-members.test.ts
index ecc827d2f8..9d9cfc1939 100644
--- a/packages/better-auth/src/plugins/organization/routes/crud-members.test.ts
+++ b/packages/better-auth/src/plugins/organization/routes/crud-members.test.ts
@@ -333,3 +333,100 @@ describe("updateMemberRole", async () => {
);
});
});
+
+describe("activeMemberRole", async () => {
+ const { auth, signInWithTestUser, cookieSetter } = await getTestInstance({
+ plugins: [organization()],
+ });
+ const ctx = await auth.$context;
+ const { headers } = await signInWithTestUser();
+ const client = createAuthClient({
+ plugins: [organizationClient()],
+ baseURL: "http://localhost:3000/api/auth",
+ fetchOptions: {
+ customFetchImpl: async (url, init) => {
+ return auth.handler(new Request(url, init));
+ },
+ },
+ });
+ const org = await client.organization.create({
+ name: "test",
+ slug: "test",
+ metadata: {
+ test: "test",
+ },
+ fetchOptions: {
+ headers,
+ },
+ });
+ const secondOrg = await client.organization.create({
+ name: "test-second",
+ slug: "test-second",
+ metadata: {
+ test: "second-org",
+ },
+ fetchOptions: {
+ headers,
+ },
+ });
+
+ let selectedUserId = "";
+ for (let i = 0; i < 10; i++) {
+ const user = await ctx.adapter.create({
+ model: "user",
+ data: {
+ email: `test${i}@test.com`,
+ name: `test${i}`,
+ },
+ });
+
+ if (i == 0) {
+ selectedUserId = user.id;
+ }
+
+ await auth.api.addMember({
+ body: {
+ organizationId: org.data?.id as string,
+ userId: user.id,
+ role: "member",
+ },
+ });
+ }
+
+ it("should return the active member role on active organization", async () => {
+ await client.organization.setActive({
+ organizationId: org.data?.id as string,
+ fetchOptions: {
+ headers,
+ },
+ });
+
+ const activeMember = await client.organization.getActiveMemberRole({
+ fetchOptions: {
+ headers,
+ },
+ });
+
+ expect(activeMember.data?.role).toBe("owner");
+ });
+
+ it("should return active member role on organization", async () => {
+ await client.organization.setActive({
+ organizationId: org.data?.id as string,
+ fetchOptions: {
+ headers,
+ },
+ });
+
+ const activeMember = await client.organization.getActiveMemberRole({
+ query: {
+ userId: selectedUserId,
+ },
+ fetchOptions: {
+ headers,
+ },
+ });
+
+ expect(activeMember.data?.role).toBe("member");
+ });
+});
diff --git a/packages/better-auth/src/plugins/organization/routes/crud-members.ts b/packages/better-auth/src/plugins/organization/routes/crud-members.ts
index 5e535c3b49..2d1e4678c4 100644
--- a/packages/better-auth/src/plugins/organization/routes/crud-members.ts
+++ b/packages/better-auth/src/plugins/organization/routes/crud-members.ts
@@ -904,3 +904,60 @@ export const listMembers = (options: O) =>
});
},
);
+
+export const getActiveMemberRole = (
+ options: O,
+) =>
+ createAuthEndpoint(
+ "/organization/get-active-member-role",
+ {
+ method: "GET",
+ query: z
+ .object({
+ userId: z
+ .string()
+ .meta({
+ description:
+ "The user ID to get the role for. If not provided, will default to the current user's",
+ })
+ .optional(),
+ organizationId: z
+ .string()
+ .meta({
+ description:
+ 'The organization ID to list members for. If not provided, will default to the user\'s active organization. Eg: "organization-id"',
+ })
+ .optional(),
+ })
+ .optional(),
+ use: [orgMiddleware, orgSessionMiddleware],
+ },
+ async (ctx) => {
+ const session = ctx.context.session;
+ const organizationId =
+ ctx.query?.organizationId || session.session.activeOrganizationId;
+ if (!organizationId) {
+ throw new APIError("BAD_REQUEST", {
+ message: ORGANIZATION_ERROR_CODES.NO_ACTIVE_ORGANIZATION,
+ });
+ }
+ const userId = ctx.query?.userId || session.user.id;
+
+ const adapter = getOrgAdapter(ctx.context, options);
+
+ const member = await adapter.findMemberByOrgId({
+ userId,
+ organizationId,
+ });
+ if (!member) {
+ throw new APIError("FORBIDDEN", {
+ message:
+ ORGANIZATION_ERROR_CODES.YOU_ARE_NOT_A_MEMBER_OF_THIS_ORGANIZATION,
+ });
+ }
+
+ return ctx.json({
+ role: member?.role,
+ });
+ },
+ );