Organizations

Roles and permissions

Your own resources, roles in nuxt.config, and roles each organization makes.
An organization's roles tab: the app's roles with their permissions, and the organization's own roles

Organization permissions are Better Auth's access control: resources with actions (project: ['create', 'update']), and roles that each allow some of them.

WhatWhere it's definedIn the UI
Resources and actionsorganization.statements in nuxt.config.tsShown on the Roles tab
App-wide roles (owner, admin, member, your own)organization.roles in nuxt.config.tsShown on the Roles tab
An organization's own rolesMade on the organization's Roles tabCreated, edited and deleted

Your resources

Better Auth comes with resources for itself: organization, member, invitation, team and ac (access control). Add your app's own with statements:

nuxt.config.ts
export default defineNuxtConfig({
  betterAuthUi: {
    organization: {
      enabled: true,
      statements: {
        project: ['create', 'share', 'update', 'delete']
      }
    }
  }
})

The module builds Better Auth's access control from them (createAccessControl) and passes it to the server and client plugins, so you don't write any of it yourself.

Resources and actions are code, not settings: Better Auth reads them when the server starts, and your app's routes are what check them. That's why they live in nuxt.config.ts rather than the UI.

Roles

Give roles their permissions with roles:

nuxt.config.ts
export default defineNuxtConfig({
  betterAuthUi: {
    organization: {
      enabled: true,
      statements: { project: ['create', 'share', 'update', 'delete'] },
      roles: {
        // A new role.
        editor: { project: ['create', 'update'] },
        // Naming owner, admin or member adds to Better Auth's role of that name.
        admin: { project: ['create', 'share', 'update', 'delete'] }
      }
    }
  }
})
  • Owners get every action on your resources, automatically.
  • Naming owner, admin or member adds permissions to Better Auth's role of that name; it doesn't replace it.
  • Role pickers (inviting, changing a member's roles) list every role.
  • Mistakes fail the build: a role naming a resource or action that isn't in statements stops the build with a message saying which.

Roles each organization makes

With dynamicRoles, an organization's owners and admins create their own roles on its Roles tab: a name, and a grid of every resource and action to tick. Better Auth's dynamic access control stores them per organization.

nuxt.config.ts
export default defineNuxtConfig({
  betterAuthUi: {
    organization: {
      enabled: true,
      statements: { project: ['create', 'share', 'update', 'delete'] },
      dynamicRoles: true // or { maximumRolesPerOrganization: 10 }
    }
  }
})
  • Creating, editing and deleting roles needs the ac:create, ac:update and ac:delete permissions; owners and admins have them.
  • Better Auth refuses permissions the editor doesn't have themselves.
  • The organization's roles join the role pickers alongside the app-wide ones.

Run Better Auth's migrations after turning it on: it adds an organizationRole table.

Checking permissions

On your server, ask Better Auth whether the signed-in member may do something in their active organization:

server/api/projects/share.post.ts
export default defineEventHandler(async (event) => {
  const { success } = await serverAuth(event).api.hasPermission({
    headers: event.headers,
    body: { permissions: { project: ['share'] } }
  })
  if (!success) throw createError({ statusCode: 403 })
})

This counts app-wide and dynamic roles alike. auth.api.getActiveMemberRole({ headers }) (or the client's organization.getActiveMemberRole()) gives the member's role itself.