user role / admin plugin
@Better Auth why is
user.role typed as role?: string | null | undefined
and not as an array of literal strings?
my auth config:
27 Replies
Better Auth is designed by default to assume that each user is assigned a single role rather than a collection of roles—hence the type is defined as an optional string (allowing for null or undefined when no role is assigned) rather than an array of literal strings [15]. This simplifies role-based permission checks throughout the framework. If your application requires multiple roles per user, you would need to extend or customize the user model accordingly, since the default configuration targets a single, primary role.
Sources:
[15] "role" field is not defined in
session.data.user.roleGitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
"role" field is not defined in
session.data.user.role · Issue #9...Is this suited for github? Yes, this is suited for github To Reproduce better-auth claims the user does not have a role type -- when it does in practice. Current vs. Expected behavior Add an option...
@Better Auth i mean not as a union of string literals, like
"owner" | "user" ?Better Auth's design leverages TypeScript's type-safety by using string literal types—so by default, roles like "owner", "admin", and "member" are defined as union types [13]. If you’re thinking of a union such as
"owner" | "user", keep in mind that the framework defines its own set of roles. However, you can always customize or extend these definitions in your own type declarations if you’d like a different union of allowed strings. Let me know if you need more details on how to configure custom role types!
Sources:
[13] Organization | Better AuthOrganization | Better Auth
The organization plugin allows you to manage your organization's members and teams.
@Better Auth why is
user.role typed as role?: string | null | undefined
and not as a union of string literals, like "owner" | "user" ?
my auth config:
Better Auth’s default behavior is to keep the type of the role field as a generic string (with the possibility of being null or undefined) so that it remains flexible. Since the framework is designed to support various customizations to the user model—where different projects might have different sets of roles—you get a generic string type by default rather than a union of specific literals like "owner" or "user" [15].
If you need a more strictly typed role (for example, a union of specific string literals), you can extend or override the default type definitions in your project to enforce that constraint. This lets you benefit from both the framework’s flexibility while also having the type safety you desire.
Sources:
[15] "role" field is not defined in
session.data.user.roleGitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
"role" field is not defined in
session.data.user.role · Issue #9...Is this suited for github? Yes, this is suited for github To Reproduce better-auth claims the user does not have a role type -- when it does in practice. Current vs. Expected behavior Add an option...
@Better Auth also why can it be
null or undefined ?Hey there! In Better Auth, you might notice that some fields are returned as either
null or undefined due to differences in how missing values are handled across various parts of the framework and external tools. For example, when using Better Auth helper functions, optional fields often default to undefined, while certain database schemas (like those from Drizzle) represent missing values as null [1].
Additionally, recent changes—such as in the token utility function—were designed to explicitly return null in cases that used to be undefined, which can lead to inconsistencies if the surrounding code expects one or the other [3]. In JavaScript/TypeScript, null indicates an intentional absence of a value, whereas undefined means a value hasn’t been set. This distinction is why you might see both appearing depending on the context or integration.
Hope this helps clear things up! Let me know if you have any other Better Auth questions.
Sources:
[1] Type mismatch between Drizzle schema and better-auth helpers
[3] Use of null breaking thingsGitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
Type mismatch between Drizzle schema and better-auth helpers · Iss...
Describe the bug The better-auth helper functions and hooks return | undefined for optional fields, whereas Drizzle returns | null. For example, this is the type of the user from authClient.useSess...
GitHub
Use of null breaking things · Issue #3559 · better-auth/better-auth
Is this suited for github? Yes, this is suited for github To Reproduce I think this commit here is braking things in my DB, and potentially others too: 7d034604 export function setTokenUtil( token:...
@Better Auth
Hi there! This error is happening because Better Auth’s API expects the role to be a strict union of specific strings (i.e., "owner" | "admin" | "user") rather than a generic string. To fix the error, you have a couple of options:
1. Cast the value explicitly when calling the API:
2. Alternatively, update your user object’s type so that the role property is typed correctly. This ensures that when you access user.role, it is already one of the expected values.
Both approaches ensure that TypeScript recognizes the role as one of the allowed values, satisfying Better Auth’s type requirements [2][6].
Let me know if you need any further help!
Sources:
[2] auth.api.userHasPermission method does throw error if no user is provided
[6] Username & admin plugin type issues
GitHub
auth.api.userHasPermission method does throw error if no user is pr...
Is this suited for github? Yes, this is suited for github To Reproduce Docs mention that userHasPermission can get userId or role but the following code throws error: await auth.api.userHasPermissi...
GitHub
Username & admin plugin type issues · Issue #3033 · better-auth/b...
I'm using better-auth in a setup where the client and server are separated (no monorepo). I've activated the username plugin on both the server and the client, and it's working as expec...
@Better Auth if i am chceking permissions like this
it wil not check the database, right?
That's right! When you pass the role directly (like
"user") along with the permissions in the request body, Better Auth will verify the permission against the static role configuration you set up in your admin plugin. It doesn't go to the database to fetch additional user details because it's using the role's predefined permissions [1], [6].
Sources:
[1] Admin | Better Auth
[6] auth.api.userHasPermission method does throw error if no user is providedGitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
Admin | Better Auth
Admin plugin for Better Auth
GitHub
auth.api.userHasPermission method does throw error if no user is pr...
Is this suited for github? Yes, this is suited for github To Reproduce Docs mention that userHasPermission can get userId or role but the following code throws error: await auth.api.userHasPermissi...
@Max do i have to use
as ... ?
@Better Auth why cant i set a user's role from the server?
APIError: You are not allowed to change users role
my code
The error
APIError: You are not allowed to change users roleindicates that the call to change a user’s role is being blocked by the admin plugin’s access control. In Better Auth, role changes (using an endpoint like setRole) are protected so that only authorized users (typically those whose IDs are listed as admins or who have the correct permission level) can modify another user’s role [8]. Here are a few things to check: 1. Verify that the request is authenticated as an admin. The admin plugin only allows role changes from users that meet the admin criteria (for example, being configured in your auth configuration’s adminUserIds or having an admin role) [8]. 2. Review your Better Auth configuration to ensure that the access control settings and admin roles are correctly set up. If your calling user isn’t recognized as having the necessary privilege, the request will fail with this error [6]. 3. Finally, if your intended use case allows a less privileged role to update roles (which is potentially risky), you may need to adjust your access control configuration. However, for security reasons, it is best to restrict role changes to highly trusted users. By ensuring that the request is coming from an appropriately privileged admin, you should be able to set the user’s role without encountering this error. Sources: [6] Ban User, userId check [8] Admin | Better Auth
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
Ban User, userId check · Issue #4648 · better-auth/better-auth
Is this suited for github? Yes, this is suited for github To Reproduce As of now when the ban user api is hit, better-auth doesn't check if the user with userId exists or not. The Server must r...
Admin | Better Auth
Admin plugin for Better Auth
@Better Auth why cant i set a user's role from the server?
APIError: You are not allowed to change users role
my code
why only an admin can set a role?
isn't a server the admin?
i just want to give user a role without depending on any adminsBetter Auth protects role changes as an administrative action, so only users explicitly granted admin permissions can update a user's role. Even when the request comes from your server, the same access control checks are applied, which is why you're seeing the error "APIError: You are not allowed to change users role" [2].
This behavior is by design to prevent unauthorized modifications from affecting your application's permission structure. Even though your server is trusted, unless it is authenticated as an admin (or using dedicated credentials like a service account meant for server-to-server admin operations [9]), the admin endpoints (like /admin/set-role) will reject role change requests from non-admin contexts.
If you want to allow role updates without having an admin manually make the request, you could consider:
- Setting up a dedicated service account with admin privileges.
- Creating a custom endpoint that bypasses the admin plugin’s checks (while keeping in mind the potential security risks).
In summary, Better Auth requires that role changes come from a validated admin session to maintain security and integrity within your authentication system [2].
Sources:
[2] Admin | Better Auth
[9] Guidance Needed: Authenticating Server-to-Server Admin API Calls (401 Unauthorized)
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
Admin | Better Auth
Admin plugin for Better Auth
GitHub
Guidance Needed: Authenticating Server-to-Server Admin API Calls (4...
Hello, I am using better-auth as the user authentication and management service for my application. My primary backend is built with Hono.js and acts as a trusted subsystem. It's important to n...
@Better Auth how do i give a user an admin role if only a user with admin role can give an admin role?
this just doesn't make sense
It might seem like a catch-22 at first, but Better Auth provides a way to break that cycle. To bootstrap your system with an admin, you can set the initial admin by using the configuration option adminUserIds. This option lets you designate one or more users as admins without needing an existing admin to assign the role [5]. Once your bootstrap admin is set up, that user can then use the admin endpoints to assign admin roles to others. This approach ensures that only trusted accounts can grant admin privileges, maintaining a secure workflow.
Sources:
[5] Custom admin role not considered an admin
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
Custom admin role not considered an admin · Issue #2015 · better-...
Is this suited for github? Yes, this is suited for github To Reproduce Configure better-auth as per the docs Add the admin plugin Add the adminRoles property with admin and superAdmin as roles Crea...
@Better Auth can i initially give a user with particular id an owner role?
No, you cannot initially assign the owner role simply by passing a particular user ID to the organization creation method. As noted in Document 1, even if you supply a userId when calling organization.create, the system will still set the currently active admin as the owner, not the specified user [1]. If you need to change the owner, you’ll have to use the role update or transfer functionality after the organization is created.
Sources:
[1] Adding userId to organization.create will not make that user the owner
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
Adding userId to organization.create will not make that user the ow...
Is this suited for github? Yes, this is suited for github To Reproduce First create a new user you want to make owner of an organization: const { data: userData, error: userError } = await authClie...
@Better Auth is there a way to setup role-based permissions without an admin plugin ?
Yes, you can set up role-based permissions without using the admin plugin. Better Auth includes a flexible access control system that you can use directly by defining roles with the createAccessControl function. For example, you can create and combine roles via ac.newRole and then perform permission checks using functions like hasPermission or checkRolePermission. This lets you enforce RBAC in your own endpoints or business logic without relying on the pre-built admin API endpoints provided by the admin plugin [1].
Sources:
[1] Admin | Better Auth
Admin | Better Auth
Admin plugin for Better Auth
@Better Auth is it okay to modify user’s role by querying db directly?
It's not recommended to modify a user's role by directly querying the database. Better Auth is designed to handle role changes through its provided APIs and plugin methods, which ensure that all necessary authorization checks, hooks, and side effects (like permission updates) are executed properly [2][4]. Bypassing these mechanisms can lead to inconsistencies or security gaps in your application.
Sources:
[2] fix(organization): allow org owner to update their own roles
[4] Owner of organization cannot update their own roles
GitHub
fix(organization): allow org owner to update their own roles by fre...
Closes #3010
Instead of only allowing users with the member:update permission to update roles, this PR also checks if the user who is updating the role has the creatorRole in which case they are al...
GitHub
Owner of organization cannot update their own roles · Issue #3010 ...
Is this suited for github? Yes, this is suited for github To Reproduce See: https://stackblitz.com/edit/stackblitz-starters-wsvsumaj?file=index.js (node ./index.js to start) Use the Organization pl...
Hey there, am facing the same exact issue here and am having a difficult time understanding this: if the
role field is added by the plugin, why don't it type it correctly according to the defined roles ? the problem with type casting is that if I add another role in the plugin I have to change it in two places.
Also, how can I infer the types of Roles and Permissions? the context is that I have a sidebar and am defining it's routes inside an array of objects containing url, title etc, amongst them I want to add a permissions prop which defines some permissions for users that can access this route.
@Better AuthHi there! The issue you're encountering is due to how Better Auth currently handles typings for custom roles. When the admin (or similar) plugin adds the
role field to the user, its TypeScript type isn’t automatically updated based on your defined roles. This means that if you add a new role via your access control configuration, TypeScript won’t “see” it unless you update the exported types as well—resulting in the need to change them in two places [6].
To resolve this, the recommended approach is to centralize your role definitions. For example, you can create your roles using the access control instance via createAccessControl and explicitly export them. This way, when you add a new role, you update it in one location only, and the exported type (or union) automatically reflects all available roles. This not only keeps your typings in sync across your application but also helps avoid having to manually cast or redefine types elsewhere.
Regarding inferring types for Roles and Permissions (like for your sidebar routes), there are a couple of approaches:
1. If your client and server are in the same project (like a monorepo), you can use the inferAdditionalFields plugin. Although its primary purpose is for additional fields, a similar strategy can be applied to keep your custom role and permission types in sync [22].
2. Alternatively, manually defining and exporting your role and permission types (for example, as a union type derived from your access control setup) ensures that any component consuming those types—like your sidebar route configuration—will have full type-safety without needing to cast types in multiple places.
By centralizing your definitions and leveraging the available type inference tools (or manually managing the types), youGitHub
Build software better, together
GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.

ensure consistency and reduce duplicated changes throughout your codebase.
Hope that clears things up! Let me know if you have any more questions.
Sources:
[6] fix: Update admin plugin documentation with code examples and comments
[22] TypeScript | Better Auth
GitHub
fix: Update admin plugin documentation with code examples and comme...
Documentation improvement for role exports and permissions array
Description
This PR adds important clarification to the documentation regarding the need to explicitly export created roles along wi...
TypeScript | Better Auth
Better Auth TypeScript integration.
i did it like this:
and

