In this snippet we will show how to expose the Spatie package permissions and roles in Vue Inertia frontend of a laravel project.
When working with Vue and inertia in a laravel project dashboard, sometimes you may need to expose the roles and permissions data to the frontend app so you can hide or toggle something based on user current role and permissions.
On the backend side you can do that in a lot of ways, for example you can apply the roles and permissions middleware:
Route::middleware(['role:Super Admin'])->group(function () {
Route::resource('users', UsersController:class);
});
Route::middleware('permission:publish posts')->get('/posts/create', ...);
However in the frontend app we need also a way to check if the user authorized to do certain action. We will build custom helpers in a vue composable file which allow us to do such this.
Open the HandleInertiaRequests.php middleware:
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
...
...
public function share(Request $request): array
{
return [
...
'auth' => [
'user' => $request->user(),
'roles' => fn () => $request->user()
? $request->user()->getRoleNames()
: [],
'permissions' => fn () => $request->user()
? $request->user()->getAllPermissions()->pluck('name')
: [],
],
...
];
}
}
In the share() method, i added other keys inside of the auth key which are roles to return the user roles, and permissions to return the user permissions,. The getRoleNames() and getAllPermissions() methods provided by Spatie package.
Permissions and Roles Composable
In the Vue app, create a new composable file resources/js/composables/useAuth.ts:
import {usePage} from "@inertiajs/vue3";
import { computed } from 'vue';
export function useAuth() {
const page = usePage();
const permissions = computed(() => page.props.auth?.permissions|| []);
const roles = computed(() => page.props.auth?.roles|| []);
const can: boolean = (permission: string) => {
return permissions.value.includes(permission)
}
const canAny: boolean = (permissionList) => {
return permissionList.some((permission: string) =>
permissions.value.includes(permission)
)
}
const hasRole: boolean = (role: string) => {
return roles.value.includes(role)
}
const hasAnyRole: boolean = (roleList) => {
return roleList.some((role: string) =>
roles.value.includes(role)
)
}
return {
permissions,
roles,
can,
canAny,
hasRole,
hasAnyRole,
}
}
The useAuth() composable returns some helper functions similar to laravels can() methods. The composable imports Inertia usePage() Api to access the page props, which in this case the props permissions and roles accessed as page.props.auth.<prop>.
Next once we have the user roles and permissions we can declare the helper functions can(), canAny(), hasRole(), etc. These functions works the same as Laravel authorization can() functions.Â
Use it in the component:
<script setup>
import { useAuth } from '@/composables/useAuth'
const { can, hasRole } = useAuth()
</script>
<template>
<button v-if="can('edit posts')">
Edit Post
</button>
<div v-if="hasRole('admin')">
Admin Panel
</div>
</template>
Make it available globally (optional):
// resources/js/app.js
import { createApp, h } from 'vue'
import { createInertiaApp, usePage } from '@inertiajs/vue3'
createInertiaApp({
setup({ el, App, props, plugin }) {
const app = createApp({
render: () => h(App, props),
})
app.use(plugin)
app.config.globalProperties.$can = (permission) => {
const page = usePage()
return page.props.auth?.permissions?.includes(permission)
}
app.mount(el)
},
})
Then:
<template>
<button v-if="$can('edit posts')">
Edit
</button>
</template>


