Skip to Content
Delmare Digital

Naming the role field

Store roles under a property other than role, such as a roles array, and have every role check in the plugin read it.

Role checks read user.role by default. To store roles under another property, such as a roles array, set roleField once on betterAuthCollections().

// Better Auth
user: { additionalFields: { roles: { type: 'string[]', input: false } } }

// Users collection
{ name: 'roles', type: 'json' }

// Payload config
betterAuthCollections({ betterAuthOptions, roleField: 'roles' })

The plugin publishes the value on config.custom.betterAuth.roleField, and every role check reads it there:

  • the first-user-admin guard
  • the saveToJWT field list
  • the access helpers (isAdmin, isAdminField, isAdminOrSelf, canUpdateOwnFields, hasRole, hasRoleField, requireAllRoles)
  • the admin login role gate
  • the API-key management gate

getRoleField(config) and DEFAULT_ROLE_FIELD ('role') are exported for your own checks.

Details

  • firstUserAdmin.roleField is the older spelling of the same setting and still works. Setting both to different values throws at startup.
  • hasAnyRole(user, roles, 'roles') and hasAllRoles take the field as a third argument; they have no config to read, and default to role when it is omitted. The other access helpers read it from the request's Payload config and accept a roleField option to override it.
  • Types: WithRoleField<User, 'roles', string[]> moves the generated role property to the configured name.
  • firstUserAdminHooks() runs inside Better Auth, outside the Payload config, so pass it roleField directly if you use it.
  • roleField is published by betterAuthCollections(). Setups that skip it have no configured value and every gate falls back to role. To use another name there, set custom: { betterAuth: { roleField: 'roles' } } on your Payload config yourself, or pass roleField to each helper and the roleField prop to a standalone LoginView.

Only the column name differs?

Better Auth's fieldName mapping (role: { type: 'string', fieldName: 'roles' }) renames where the value is stored, and the adapter handles it. In this plugin the stored name is also the Payload field name, so Payload-side checks see user.roles while Better Auth's session user keeps role. Set roleField to the stored name ('roles'); the admin login gate translates it to the session key on its own.

Use fieldName for a column rename under Better Auth's key. Use roleField when the property itself has another name.

Added in 0.13.2.

Edit this page on GitHub

On this page