Lucid mixin
Add assignRole / can / getRoles sugar directly to your user model.
The optional hasPermissions mixin (exported from the @adonis-agora/authz/mixins
subpath) adds RBAC sugar to a Lucid model. Every method delegates to the
AuthzService and the store.
import { compose } from '@adonisjs/core/helpers'
import { BaseModel } from '@adonisjs/lucid/orm'
import { hasPermissions } from '@adonis-agora/authz/mixins'
import { AuthzService } from '@adonis-agora/authz'
import app from '@adonisjs/core/services/app'
export default class User extends compose(
BaseModel,
hasPermissions(() => app.container.make(AuthzService)),
) {
// ...your columns
}The factory takes a resolver (sync or async) for the AuthzService. It needs the
service class rather than the
services/main singleton, because
the write helpers (assignRole, givePermission, …) go through service.store,
which the singleton does not carry.
Methods
const user = await User.findOrFail(1)
await user.assignRole('editor')
await user.assignRole('viewer', { tenantId: 'acme' })
await user.removeRole('editor')
await user.givePermission('billing.view') // direct grant
await user.revokePermission('billing.view')
await user.getRoles() // string[]
await user.getPermissions() // string[] (role-derived ∪ direct)
await user.can('posts.edit') // wildcard-aware boolean
await user.hasRole('admin')The mixin maps the model to a { type, id } reference using the configured
resolveUserRef. The default reads this.id; set a type via
resolveUserRef if you store multiple subject kinds.
Every method above is one query for one user. Over a list of users, getRoles()
becomes one round trip per row — for that case declare a
roles relation and preload it.
React / Inertia
Client-side authorization for Inertia + React — AuthzProvider, useAuthz, useCan, the <Can> gating component, and the server-side buildAuthzShare() that pushes effective grants to the frontend.
Roles relation
authzRolesRelation() — the Lucid manyToMany options that join your user model to the authz roles through the authz_user_role pivot, so a listing preloads roles instead of asking once per user.