---
title: Admin
description: Admin plugin for Better Auth
---

The Admin plugin provides a set of administrative functions for user management in your application. It allows administrators to perform various operations such as creating users, managing user roles, banning/unbanning users, impersonating users, and more.

## Installation

<Steps>
  <Step>
    ### Add the plugin to your auth config

    To use the Admin plugin, add it to your auth config.

    ```ts title="auth.ts"
    import { betterAuth } from "better-auth"
    import { admin } from "better-auth/plugins" // [!code highlight]

    export const auth = betterAuth({
        // ... other config options
        plugins: [
            admin() // [!code highlight]
        ]
    })
    ```

  </Step>

    <Step>
        ### Migrate the database

        Run the migration or generate the schema to add the necessary fields and tables to the database.

        <Tabs items={["migrate", "generate"]}>
            <Tab value="migrate">
            ```bash
            npx @better-auth/cli migrate
            ```
            </Tab>
            <Tab value="generate">
            ```bash
            npx @better-auth/cli generate
            ```
            </Tab>
        </Tabs>
        See the [Schema](#schema) section to add the fields manually.
    </Step>

  <Step>
    ### Add the client plugin

    Next, include the admin client plugin in your authentication client instance.

    ```ts title="auth-client.ts"
    import { createAuthClient } from "better-auth/client"
    import { adminClient } from "better-auth/client/plugins"

    const authClient = createAuthClient({
        plugins: [
            adminClient()
        ]
    })
    ```

  </Step>
</Steps>

## Usage

Before performing any admin operations, the user must be authenticated with an admin account. An admin is any user assigned the `admin` role or any user whose ID is included in the `adminUserIds` option.

### Create User

Allows an admin to create a new user.

```ts title="admin.ts"
const newUser = await authClient.admin.createUser({
  name: "Test User",
  email: "test@example.com",
  password: "password123",
  role: "user",
  data: {
    // any additional on the user table including plugin fields and custom fields
    customField: "customValue",
  },
});
```

### List Users

Allows an admin to list all users in the database.

```ts title="admin.ts"
const users = await authClient.admin.listUsers({
  query: {
    limit: 10,
  },
});
```

By default, 100 users are returned. You can adjust the limit and offset using the following query parameters:

- `search`: The search query to apply to the users. It can be an object with the following properties:
  - `field`: The field to search on, which can be `email` or `name`.
  - `operator`: The operator to use for the search. It can be `contains`, `starts_with`, or `ends_with`.
  - `value`: The value to search for.
- `limit`: The number of users to return.
- `offset`: The number of users to skip.
- `sortBy`: The field to sort the users by.
- `sortDirection`: The direction to sort the users by. Defaults to `asc`.
- `filter`: The filter to apply to the users. It can be an array of objects.

```ts title="admin.ts"
const users = await authClient.admin.listUsers({
    query: {
        searchField: "email",
        searchOperator: "contains",
        searchValue: "@example.com",
        limit: 10,
        offset: 0,
        sortBy: "createdAt",
        sortDirection: "desc"
        filterField: "role",
        filterOperator: "eq",
        filterValue: "admin"
    }
});
```

#### Pagination

The `listUsers` function supports pagination by returning metadata alongside the user list. The response includes the following fields:  

```ts
{
  users: User[],   // Array of returned users
  total: number,   // Total number of users after filters and search queries
  limit: number | undefined,   // The limit provided in the query
  offset: number | undefined   // The offset provided in the query
}
```

##### How to Implement Pagination  

To paginate results, use the `total`, `limit`, and `offset` values to calculate:  

- **Total pages:** `Math.ceil(total / limit)`  
- **Current page:** `(offset / limit) + 1`  
- **Next page offset:** `Math.min(offset + limit, (total - 1))` – The value to use as `offset` for the next page, ensuring it does not exceed the total number of pages.
- **Previous page offset:** `Math.max(0, offset - limit)` – The value to use as `offset` for the previous page (ensuring it doesn’t go below zero).

##### Example Usage  

Fetching the second page with 10 users per page:  

```ts title="admin.ts"
const pageSize = 10;
const currentPage = 2;

const users = await authClient.admin.listUsers({
    query: {
        limit: pageSize,
        offset: (currentPage - 1) * pageSize
    }
});

const totalUsers = users.total;
const totalPages = Math.ceil(totalUsers / limit)
```

### Set User Role

Changes the role of a user.

```ts title="admin.ts"
const updatedUser = await authClient.admin.setRole({
  userId: "user_id_here",
  role: "admin",
});
```

### Ban User

Bans a user, preventing them from signing in and revokes all of their existing sessions.

```ts title="admin.ts"
const bannedUser = await authClient.admin.banUser({
  userId: "user_id_here",
  banReason: "Spamming", // Optional (if not provided, the default ban reason will be used - No reason)
  banExpiresIn: 60 * 60 * 24 * 7, // Optional (if not provided, the ban will never expire)
});
```

### Unban User

Removes the ban from a user, allowing them to sign in again.

```ts title="admin.ts"
const unbannedUser = await authClient.admin.unbanUser({
  userId: "user_id_here",
});
```

### List User Sessions

Lists all sessions for a user.

```ts title="admin.ts"
const sessions = await authClient.admin.listUserSessions({
  userId: "user_id_here",
});
```

### Revoke User Session

Revokes a specific session for a user.

```ts title="admin.ts"
const revokedSession = await authClient.admin.revokeUserSession({
  sessionToken: "session_token_here",
});
```

### Revoke All Sessions for a User

Revokes all sessions for a user.

```ts title="admin.ts"
const revokedSessions = await authClient.admin.revokeUserSessions({
  userId: "user_id_here",
});
```

### Impersonate User

This feature allows an admin to create a session that mimics the specified user. The session will remain active until either the browser session ends or it reaches 1 hour. You can change this duration by setting the `impersonationSessionDuration` option.

```ts title="admin.ts"
const impersonatedSession = await authClient.admin.impersonateUser({
  userId: "user_id_here",
});
```

### Stop Impersonating User

To stop impersonating a user and continue with the admin account, you can use `stopImpersonating`

```ts title="admin.ts"
await authClient.admin.stopImpersonating();
```

### Remove User

Hard deletes a user from the database.

```ts title="admin.ts"
const deletedUser = await authClient.admin.removeUser({
  userId: "user_id_here",
});
```

## Access Control

The admin plugin offers a highly flexible access control system, allowing you to manage user permissions based on their role. You can define custom permission sets to fit your needs.

### Roles

By default, there are two roles:

`admin`: Users with the admin role have full control over other users.

`user`: Users with the user role have no control over other users.

### Permissions

By default, there are two resources with up to six permissions.

**user**:
  `create` `list` `set-role` `ban` `impersonate` `delete` `set-password`

**session**:
  `list` `revoke` `delete`

The admin have full control over all the resources and actions. The user have no control over any of those actions.

### Custom Permissions

the plugin providers easy way to define your own set of permission for each role.

<Steps>
    <Step>
    #### Create Access Control

    You first need to create access controller by calling `createAccessControl` function and passing the statement object. The statement object should have the resource name as the key and the array of actions as the value.
    ```ts title="permissions.ts"
    import { createAccessControl } from "better-auth/plugins/access";

    /**
     * make sure to use `as const` so typescript can infer the type correctly
     */
    const statement = { // [!code highlight]
        project: ["create", "share", "update", "delete"], // [!code highlight]
    } as const; // [!code highlight]

    const ac = createAccessControl(statement); // [!code highlight]
    ```
    </Step>

    <Step>
    #### Create Roles

    Once you have created the access controller you can create roles with the permissions you have defined.

    ```ts title="permissions.ts"
    import { createAccessControl } from "better-auth/plugins/access";

    const statement = {
        project: ["create", "share", "update", "delete"],
    } as const;

    const ac = createAccessControl(statement);

    const user = ac.newRole({ // [!code highlight]
        project: ["create"], // [!code highlight]
    }); // [!code highlight]

    const admin = ac.newRole({ // [!code highlight]
        project: ["create", "update"], // [!code highlight]
    }); // [!code highlight]

    const myCustomRole = ac.newRole({ // [!code highlight]
        project: ["create", "update", "delete"], // [!code highlight]
        user: ["ban"], // [!code highlight]
    }); // [!code highlight]
    ```

      When you create custom roles for existing roles, the predefined permissions for those roles will be overridden. To add the existing permissions to the custom role, you need to import `defaultStatements` and merge it with your new statement, plus merge the roles' permissions set with the default roles.

    ```ts title="permissions.ts"
    import { createAccessControl } from "better-auth/plugins/access";
    import { defaultStatements, adminAc } from "better-auth/plugins/admin/access";

    const statement = {
        ...defaultStatements, // [!code highlight]
        project: ["create", "share", "update", "delete"],
    } as const;

    const ac = createAccessControl(statement);

    const admin = ac.newRole({
        project: ["create", "update"],
        ...adminAc.statements, // [!code highlight]
    });
    ```

    </Step>

    <Step>
        #### Pass Roles to the Plugin

        Once you have created the roles you can pass them to the organization plugin both on the client and the server.

        ```ts title="auth.ts"
        import { ac, admin, user } from "@/auth/permissions"
        import { betterAuth } from "better-auth"
        import { admin } from "better-auth/plugins"

        export const auth = betterAuth({
            plugins: [
                admin({
                    ac: ac,
                    roles: {
                        admin,
                        user,
                        myCustomRole
                    }
                }),
            ],
        });
        ```

        You also need to pass the access controller and the roles to the client plugin.

        ```ts title="auth-client.ts"
        import { createAuthClient } from "better-auth/client"
        import { adminClient } from "better-auth/client/plugins"
        import { ac, admin, user, myCustomRole } from "@/auth/permissions"

        export const client = createAuthClient({
            plugins: [
                adminClient({
                    ac: ac,
                    roles: {
                        admin,
                        user,
                        myCustomRole
                    }
                })
            ]
        })
        ```
    </Step>

</Steps>

### Access Control Usage

**Has Permission**:

To check the permission of the user, you can use the `hasPermission` function provided by the client.

```ts title="auth-client.ts"
const canCreateProject = await authClient.admin.hasPermission({
  permission: {
    project: ["create"],
  },
});
```

If you want to use the server instead to check if a user has a permission, you can use `adminHasPermission` action provided by the `api` to check the permission of the user.

```ts title="api.ts"
import { auth } from "@/auth";
auth.api.adminHasPermission({
  body: {
    userId: 'id', //the user id
    permission: {
      project: ["create"], // This must match the structure in your access control
    },
  },
});

//you can also just pass the role directly
auth.api.adminHasPermission({
  body: {
   role: "admin",
    permission: {
      project: ["create"], // This must match the structure in your access control
    },
  },
});
```


**Check Role Permission**:

Once you have defined the roles and permissions to avoid checking the permission from the server you can use the `checkRolePermission` function provided by the client.

```ts title="auth-client.ts"
const canCreateProject = client.admin.checkRolePermission({
  permission: {
    user: ["delete"],
  },
  role: "admin",
});
```

## Schema

This plugin adds the following fields to the `user` table:

<DatabaseTable
  fields={[
    {
      name: "role",
      type: "string",
      description:
        "The user's role. Defaults to `user`. Admins will have the `admin` role.",
      isOptional: true,
    },
    {
      name: "banned",
      type: "boolean",
      description: "Indicates whether the user is banned.",
      isOptional: true,
    },
    {
      name: "banReason",
      type: "string",
      description: "The reason for the user's ban.",
      isOptional: true,
    },
    {
      name: "banExpires",
      type: "number",
      description: "The Unix timestamp when the user's ban will expire.",
      isOptional: true,
    },
  ]}
/>

And adds one field in the `session` table:

<DatabaseTable
  fields={[
    {
      name: "impersonatedBy",
      type: "string",
      description: "The ID of the admin that is impersonating this session.",
      isOptional: true,
    },
  ]}
/>

## Options

### Default Role

The default role for a user. Defaults to `user`.

```ts title="auth.ts"
admin({
  defaultRole: "regular",
});
```

### Admin userIds

You can pass an array of userIds that should be considered as admin. Default to `[]`

```ts title="auth.ts"
admin({
    adminUserIds: ["user_id_1", "user_id_2"]
})
```

### impersonationSessionDuration

The duration of the impersonation session in seconds. Defaults to 1 hour.

```ts title="auth.ts"
admin({
  impersonationSessionDuration: 60 * 60 * 24, // 1 day
});
```

### Default Ban Reason

The default ban reason for a user created by the admin. Defaults to `No reason`.

```ts title="auth.ts"
admin({
  defaultBanReason: "Spamming",
});
```

### Default Ban Expires In

The default ban expires in for a user created by the admin in seconds. Defaults to `undefined` (meaning the ban never expires).

```ts title="auth.ts"
admin({
  defaultBanExpiresIn: 60 * 60 * 24, // 1 day
});
```
