Agora

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.

app/models/user.ts
import { compose } from '@adonisjs/core/helpers'
import { BaseModel } from '@adonisjs/lucid/orm'
import { hasPermissions } from '@adonis-agora/authz/mixins'

export default class User extends compose(BaseModel, hasPermissions()) {
  // ...your columns
}

That is all the wiring. The mixin uses the app's authz service, reached on the first call — never when the model file loads. To use another service (a test that builds one by hand, for instance), pass a resolver: hasPermissions(() => service).

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 resolveSubjectRef. The default reads this.id; set a type via resolveSubjectRef if you store multiple subject kinds.

can() and hasRole() go through the service, so inside a request they share the request's permission cache: a role or permission assigned after the request's first check for that user is seen from the next request, not by later checks in the same one. getRoles() and getPermissions() read the store directly on every call.

The read methods are 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.

On this page

Partner

Your product as the official integration for Authz, right here.

Become a partner →