usePermissions
Role-based access control with actions, subjects, and context-aware conditions.
Installation
Install the Permissions plugin in your app’s entry point:
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:
<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:
<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.
| Adapter | Import | Description |
|---|---|---|
Vuetify0PermissionAdapter | @vuetify/v0/permissions/adapters/v0 | Token-based permission lookup (default) |
Custom Adapters
Implement the PermissionAdapter abstract class to integrate any backend authorization system:
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:
Reactivity
Permissions are stored in a token registry. There are no reactive properties — all interactions are through lookup methods (can(), get(), has()).
Using with reactive state Wrap can() in a computed to react to permission changes:
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 | read | write | delete |
|---|---|---|---|
| user | ✓ | ✕ | ✕ |
| post | ✓ | ✓ | ✕ |
Context-aware check
editor + delete + post (owner): true
editor + delete + post (not owner): false
Functions
createPermissions
(_options?: PermissionOptions) => PermissionContext<PermissionTicket>Creates a new permissions instance.
createPermissionsContext
<_E>(_options?: PermissionContextOptions | undefined) => ContextTrinity<_E>createPermissionsPlugin
(_options?: PermissionContextOptions | undefined) => PluginusePermissions
<_E>(namespace?: string) => _EOptions
adapter
PermissionAdapter | undefinedpermissions
Record<ID, [string | string[], string | string[], (boolean | ((context: Record<string, unknown>) => boolean) | undefined)?][]> | undefinedProperties
Methods
move
(id: ID, toIndex: number) => E | undefinedSeek for a ticket based on direction and optional predicate
seek
(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefinedon
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidListen for registry events
off
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidStop listening for registry events
emit
<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => voidEmit an event with data
batch
<R>(fn: () => R) => RExecute operations in a batch, deferring cache invalidation and event emission until complete
can
(id: ID, action: string, subject: string, context?: Record<string, unknown>) => boolean