Skip to main content
Vuetify0 is now in alpha!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

usePermissions

Role-based access control with actions, subjects, and context-aware conditions.

Installation

Install the Permissions plugin in your app’s entry point:

main.ts
import { createApp } from 'vue'
import { createPermissionsPlugin } from '@vuetify/v0'
import App from './App.vue'

const app = createApp(App)

app.use(
  createPermissionsPlugin({
    permissions: {
      admin: [
        [['read', 'write'], 'user', true],
        [['read', 'write'], 'post', true],
        ['delete', ['user', 'post'], true],
      ],
      editor: [
        [['read', 'write'], 'post', true],
        ['read', 'user', true],
        ['delete', 'post', (context) => context.isOwner],
      ],
      viewer: [
        ['read', ['user', 'post'], true],
      ],
    },
  })
)

app.mount('#app')

Usage

Once the plugin is installed, check permissions for specific roles in any component:

UsePermissions
<script setup lang="ts">
  import { usePermissions } from '@vuetify/v0'

  const permissions = usePermissions()
  const currentUser = { role: 'editor', id: 'user123' }
</script>

<template>
  <div>
    <button v-if="permissions.can('admin', 'delete', 'user')">
      Delete User (Admin Only)
    </button>

    <button v-if="permissions.can('editor', 'write', 'post')">
      Edit Post
    </button>

    <button
      v-if="permissions.can('editor', 'delete', 'post', { isOwner: true })"
    >
      Delete Own Post
    </button>
  </div>
</template>

Optionally register permissions at runtime:

UsePermissions
<script setup lang="ts">
  import { usePermissions } from '@vuetify/v0'

  const permissions = usePermissions()

  // Register permission at runtime
  permissions.register({
    id: 'moderator.ban.user',
    value: (context) => context.userLevel < 3
  })

  // Check the permission
  const canBan = permissions.can('moderator', 'ban', 'user', { userLevel: 2 })
</script>

Adapters

Adapters let you swap the underlying permission resolution strategy without changing your application code.

AdapterImportDescription
Vuetify0PermissionAdapter@vuetify/v0/permissions/adapters/v0Token-based permission lookup (default)

Custom Adapters

Implement the PermissionAdapter abstract class to integrate any backend authorization system:

src/adapters/my-permission-adapter.ts
import { PermissionAdapter } from '@vuetify/v0/permissions/adapters/v0'
import type { PermissionContext, PermissionTicket } from '@vuetify/v0'
import type { ID } from '@vuetify/v0'

class MyPermissionAdapter extends PermissionAdapter {
  can<Z extends PermissionTicket>(
    role: ID,
    action: string,
    subject: string,
    context: Record<string, any>,
    permissions: PermissionContext<Z>,
  ): boolean {
    // Delegate to your auth system
    return myAuthClient.check(String(role), `${action}:${subject}`, context)
  }
}

// Use with plugin
app.use(
  createPermissionsPlugin({
    adapter: new MyPermissionAdapter(),
  })
)

Architecture

usePermissions uses createTokens for permission flattening and lookup:

Permissions Flow

Use controls to zoom and pan. Click outside or press Escape to close.

Permissions Flow

Reactivity

Permissions are stored in a token registry. There are no reactive properties — all interactions are through lookup methods (can(), get(), has()).

Tip

Using with reactive state Wrap can() in a computed to react to permission changes:

ts
const canEdit = computed(() => permissions.can(user.role, 'edit', 'post'))

Examples

Role Checker

Displays a matrix of resource/action permissions per role, using can() inside a computed to reactively reflect the active role’s access level.

Subject readwritedelete
user
post

Context-aware check

editor + delete + post (owner): true

editor + delete + post (not owner): false

API Reference

The following API details are for the usePermissions composable.

Functions

createPermissions

(_options?: PermissionOptions) => PermissionContext<PermissionTicket>

Creates a new permissions instance.

createPermissionsContext

<_E>(_options?: PermissionContextOptions | undefined) => ContextTrinity<_E>

createPermissionsPlugin

(_options?: PermissionContextOptions | undefined) => Plugin

usePermissions

<_E>(namespace?: string) => _E

Options

events

boolean | undefined

Enable event emission for registry operations

Default: false

reactive

boolean | undefined

Enable reactive behavior for registry operations

Default: false

flat

boolean | undefined

Whether to flatten nested token structures.

Default: false

prefix

string | undefined

An optional prefix to prepend to each token ID during registration.

adapter

PermissionAdapter | undefined

permissions

Record<ID, [string | string[], string | string[], (boolean | ((context: Record<string, unknown>) => boolean) | undefined)?][]> | undefined

Properties

collection

ReadonlyMap<ID, E>

The collection of tickets in the registry

size

number

The number of tickets in the registry

Methods

clear

() => void

Clear the entire registry

has

(id: ID) => boolean

Check if a ticket exists by ID

keys

() => readonly ID[]

Get all registered IDs

browse

(value: E["value"]) => ID[] | undefined

Browse for an ID(s) by value

lookup

(index: number) => ID | undefined

lookup a ticket by index number

get

(id: ID) => E | undefined

Get a ticket by ID

upsert

(id: ID, ticket?: Partial<Z>, event?: string) => E

Update or insert a ticket by ID

values

() => readonly E[]

Get all values of registered tickets

entries

() => readonly [ID, E][]

Get all entries of registered tickets

register

(ticket?: Partial<Z & RegistryTicket>) => E

Register a new ticket

unregister

(id: ID) => void

Unregister a ticket by ID

reindex

() => void

Reset the index directory and update all tickets

move

(id: ID, toIndex: number) => E | undefined

Seek for a ticket based on direction and optional predicate

seek

(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefined

on

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Listen for registry events

off

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Stop listening for registry events

emit

<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => void

Emit an event with data

dispose

() => void

Clears the registry and removes all listeners

onboard

(registrations: Partial<Z & RegistryTicket>[]) => E[]

Onboard multiple tickets at once

offboard

(ids: ID[]) => void

Offboard multiple tickets at once

batch

<R>(fn: () => R) => R

Execute operations in a batch, deferring cache invalidation and event emission until complete

isAlias

(token: unknown) => token is string

Checks if a token is an alias

resolve

(token: string | TokenAlias) => unknown | undefined

Resolves a token or alias to its value.

can

(id: ID, action: string, subject: string, context?: Record<string, unknown>) => boolean
Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/