mlsolutions/sanctum-tokens
A Laravel package for working with Sanctum API tokens, providing convenient helpers and endpoints to create, list, and revoke tokens while keeping token management simple and consistent across your application. Designed to integrate smoothly with existing Sanctum setups.
Prerequisites
laravel/sanctum installed and migrated (php artisan migrate after publishing Sanctum's migration).Laravel\Sanctum\HasApiTokens trait on the model that will own tokens (usually App\Models\User).composer.json constraints in the repo against your Laravel/Nova versions before installing — this is a single-maintainer package with one release, so version support may lag.Install and register
composer require mlsolutions/sanctum-tokens
Then follow the README's registration step. Nova packages of this shape usually register one of three ways:
app/Providers/NovaServiceProvider.php → tools([...]).fields() of your User resource (so it appears on the user detail page).Verify which by reading src/ and the service provider — the registration snippet in the README is the single source of truth here. After registering, run php artisan nova:publish if the package ships frontend assets, and clear caches (php artisan optimize:clear) if the tool doesn't appear.
First use case
The canonical day-to-day scenario: an admin opens a User in Nova, clicks the token panel, creates a token with a name and (optionally) abilities, and copies the plaintext token once from the UI to hand to an integration owner. Everything after that is lifecycle: listing tokens with last_used_at, revoking stale ones.
Where to look first
src/ service provider — tells you whether it's a tool, field, or resource, and what config it reads.config/ (if publishable) — defaults for abilities, expiration, model binding.personal_access_tokens table, since that's the data contract underneath.Attach to the User resource (most common)
Add the package's field/tool to app/Nova/User.php and keep it in a ->onlyOnDetail() context so it doesn't clutter index views. A typical detail page then shows: token name, abilities, created_at, last_used_at, expires_at, and a revoke button.
Scoped abilities instead of wildcard
When creating tokens through the UI, pass explicit abilities (['orders:read', 'orders:write']) rather than ['*']. Then in your API layer check $request->user()->tokenCan('orders:read') instead of relying on role checks. This is the main reason to use tokens over session auth for integrations: the blast radius of a leaked token is bounded.
Expiration strategy
Sanctum has a global sanctum.expiration (minutes) and a per-token expires_at. Decide which you're using before rollout:
expires_at set at creation: better for contracts and audits; store the intent in the token name ("acme-sync-2025-06").Admin/support workflow
Treat token creation as a privileged operation. Gate it with a policy or Gate check so only specific Nova roles can mint tokens for other users. A support agent being able to mint a token as any user is effectively full account impersonation for your API.
// app/Policies/UserPolicy.php
public function createToken(User $user, User $target): bool
{
return $user->hasRole('admin');
}
Bulk operations via Nova Actions
For day-to-day hygiene, pair the package with a Nova Action on the User resource that revokes tokens where last_used_at is older than N days or expires_at < now(). The package handles creation; revocation is just $user->tokens()->where(...)->delete().
Programmatic creation (scripts, seeders, tests)
Don't route everything through Nova. For service accounts and local dev:
$token = $user->createToken('local-dev', ['orders:read'], now()->addMonth());
// $token->plainTextToken — only available here, once
Testing token auth
Sanctum::actingAs($user, ['orders:read']);
$this->getJson('/api/orders')->assertOk();
$this->getJson('/api/orders')->assertForbidden(); // wrong ability
For Nova-side tests, actingAs($admin) plus a post to whatever endpoint the tool registers (check routes/ in the package or Nova's tool endpoint convention).
The plaintext token is shown once, and only once. Sanctum stores a SHA-256 hash. If your UI flow loses it (page refresh, modal closed, copy failed), the only recovery is delete-and-recreate. Make sure the Nova component surfaces the token in a copy-to-clipboard field before dismissing, and warn users in the UI copy.
Don't confuse this with user-facing API keys. This package is an admin-plane tool. If end users need self-service API keys, build that in your app's own UI — you don't want the token lifecycle coupled to Nova availability or Nova permissions.
Privilege escalation is the real risk. Nova access ≠ permission to impersonate. Default-deny: only admins mint tokens, and log who created which token (the base table doesn't record a creator — add a created_by column via your own migration if you need an audit trail, or log to your activity log at creation time).
Package maturity. Zero stars, one release, single maintainer. Practical implications:
composer.json ("mlsolutions/sanctum-tokens": "1.0.*"), don't use ^ against a 0.x-style version range.src/ before installing — it's small enough to audit in ten minutes.composer.json require block explicitly for Laravel/Nova majors; a missing constraint will silently install on an unsupported version and fail at runtime.Sanctum config interactions. SANCTUM_STATEFUL_DOMAINS and the sanctum.guard config affect whether tokenCan() behaves as you expect. If a freshly created token returns 401, check: correct guard, Authorization: Bearer <token>, token not expired, and the personal_access_tokens row exists with the right tokenable_type.
last_used_at is lazy. Sanctum updates it on authenticated requests, but not on every request in every version — don't build "active tokens" dashboards that assume second-level accuracy. For revocation campaigns, use a window (e.g. "unused in 90 days"), not a strict threshold.
Soft deletes and morphs. If your User model is soft-deletable, tokens survive deletion and tokenable resolution will fail or return a trashed model depending on your queries. Decide whether to cascade-delete tokens in deleting/forceDeleting hooks.
Extension points to prefer over patching. Override the Nova resource/field in your app rather than editing vendor/. If the package publishes config (php artisan vendor:publish --provider="MlSolutions\\SanctumTokens\\...ServiceProvider"), change abilities defaults and expiration there. If it doesn't publish config, wrap its behavior in your own Nova Action — that's the most upgrade-safe integration.
Debugging checklist when a token "doesn't work":
personal_access_tokens? (tokenable_id, abilities JSON).expires_at null or in the future?auth:sanctum middleware?tokenCan() returning false because abilities were stored as a JSON string vs array (check the cast)?How can I help you explore Laravel packages today?