Limit a Sanctum token with abilities

createToken can take an ability list. The ability middleware belongs on the API route, not on an Inertia page.

For your AI agent

Copies a prompt. Paste it into the AI agent you already have open.

Read https://laravel-vuejs.space/sanctum-token-abilities-vue.md
createToken can take an ability list. The ability middleware belongs on the API route, not on an Inertia page.
Do not call it from an Inertia controller and hide the button based on it.
Do not treat abilities as a substitute for a policy.
Show the diff. Do not commit.
On this page · 3 sections
  1. The fix
  2. What to avoid
  3. FAQ

People searching “Sanctum token abilities” put abilities:posts:read on a browser route and then every Inertia page returns 403. Abilities exist on a token. A session does not have them. The Sanctum guide is the cookie. This page is the token.

TL;DR

  • createToken can take an ability list.
  • The ability middleware belongs on the API route, not on an Inertia page.
  • Do not call it from an Inertia controller and hide the button based on it.
  • Do not treat abilities as a substitute for a policy.

Who it's for: Laravel + Vue developers

Applies to: Laravel 13 · Vue 3 · Sanctum

The fix#

php
$plain = $request->user()->createToken('phone', ['posts:read'])->plainTextToken;
php
Route::get('/posts', [Api\PostController::class, 'index'])
    ->middleware(['auth:sanctum', 'abilities:posts:read']);

That route lives in routes/api.php. The Vue starter kit’s pages stay on routes/web.php with auth.

In a controller that must be picky inside an action, $request->user()->tokenCan('posts:read') checks the current token. It is false for a session guard. Do not call it from an Inertia controller and hide the button based on it.

What to avoid#

Gotcha

Do not treat abilities as a substitute for a policy. An ability is what that token may do. A policy is what that user may do to a row.

FAQ#

How do I limit a Sanctum token with abilities?

createToken can take an ability list. The ability middleware belongs on the API route, not on an Inertia page.

What goes wrong with Sanctum token abilities?

Many developers put abilities:posts:read on a browser route and then every Inertia page returns 403. Do not call it from an Inertia controller and hide the button based on it.

Found this useful?

Ask questions, share what you built.

Join thousands of Laravel and Vue developers in our Facebook group, or get new posts in your Telegram feed. Sharing this article helps too.

Keep reading

Newsletter

Get the best of Laravel & Vue, once a month.

One short email with new guides, release notes worth reading and hand-picked community links. No spam, unsubscribe any time.