diff --git a/docs/content/docs/plugins/admin.mdx b/docs/content/docs/plugins/admin.mdx
index 23ab5084..e9a9e339 100644
--- a/docs/content/docs/plugins/admin.mdx
+++ b/docs/content/docs/plugins/admin.mdx
@@ -514,6 +514,20 @@ admin({
defaultRole: "regular",
});
```
+### Admin Roles
+
+The roles that are considered admin roles. Defaults to `["admin"]`.
+
+```ts title="auth.ts"
+admin({
+ adminRoles: ["admin", "superadmin"],
+});
+```
+
+
+ Any role that isn't in the `adminRoles` list, even if they have the permission,
+ will not be considered an admin.
+
### Admin userIds
@@ -525,6 +539,8 @@ admin({
})
```
+If a user is in the `adminUserIds` list, they will be able to perform any admin operation.
+
### impersonationSessionDuration
The duration of the impersonation session in seconds. Defaults to 1 hour.
diff --git a/packages/better-auth/src/plugins/admin/admin.test.ts b/packages/better-auth/src/plugins/admin/admin.test.ts
index 9ad91222..5ef0b60a 100644
--- a/packages/better-auth/src/plugins/admin/admin.test.ts
+++ b/packages/better-auth/src/plugins/admin/admin.test.ts
@@ -290,7 +290,7 @@ describe("Admin plugin", async () => {
},
});
//should reject cause the user is not admin
- expect(impersonatedUserRes.error?.status).toBe(403);
+ expect(impersonatedUserRes.error?.status).toBe(401);
const res = await client.admin.stopImpersonating(
{},
{
diff --git a/packages/better-auth/src/plugins/admin/admin.ts b/packages/better-auth/src/plugins/admin/admin.ts
index b798243e..dec3b2f5 100644
--- a/packages/better-auth/src/plugins/admin/admin.ts
+++ b/packages/better-auth/src/plugins/admin/admin.ts
@@ -18,7 +18,6 @@ import { getDate } from "../../utils/date";
import { getEndpointResponse } from "../../utils/plugin-helper";
import { mergeSchema } from "../../db/schema";
import { type AccessControl, type Role } from "../access";
-import { adminMiddleware } from "./call";
import { ADMIN_ERROR_CODES } from "./error-codes";
import { defaultStatements } from "./access";
import { hasPermission } from "./has-permission";
@@ -41,6 +40,15 @@ export interface AdminOptions {
* @default "user"
*/
defaultRole?: string;
+ /**
+ * Roles that are considered admin roles.
+ *
+ * Any user role that isn't in this list, even if they have the permission,
+ * will not be considered an admin.
+ *
+ * @default ["admin"]
+ */
+ adminRoles?: string | string[];
/**
* A default ban reason
*
@@ -85,12 +93,32 @@ export interface AdminOptions {
export const admin = (options?: O) => {
const opts = {
defaultRole: "user",
+ adminRoles: ["admin"],
...options,
};
type DefaultStatements = typeof defaultStatements;
type Statements = O["ac"] extends AccessControl
? S
: DefaultStatements;
+
+ const adminMiddleware = createAuthMiddleware(async (ctx) => {
+ const session = await getSessionFromCtx(ctx);
+ if (
+ (!session?.session || !opts.adminRoles.includes(session.user.role)) &&
+ !opts.adminUserIds?.includes(session?.session?.user.id)
+ ) {
+ throw new APIError("UNAUTHORIZED");
+ }
+ return {
+ session,
+ } as {
+ session: {
+ user: UserWithRole;
+ session: Session;
+ };
+ };
+ });
+
return {
id: "admin",
init(ctx) {