metasync-site/sanctum-tokens
Manage Sanctum API tokens from the command line: list, create, rotate, and revoke tokens for any user, with expiry controls and a clean Artisan interface for Laravel apps.
Install the package alongside the two things it assumes already exist:
composer require metasync-site/sanctum-tokens
php artisan vendor:publish --provider="MetasyncSite\SanctumTokens\SanctumTokensServiceProvider"
Verify Sanctum itself is installed and migrated first (php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" && php artisan migrate). Without the personal_access_tokens table this package has nothing to write to.
Register the action on your User (or whatever authenticatable model issues tokens) Nova resource. The package ships a Nova action class; add it to the actions() list:
public function actions(NovaRequest $request)
{
return [new \MetasyncSite\SanctumTokens\Actions\CreateToken()];
}
Registration is the "look here first" step — if the action doesn't appear, either the class name / namespace has drifted (this package has few releases, so check the source), or Nova isn't discovering it because you registered it on the wrong resource.
First use case: open a user record in Nova → Actions dropdown → Create Token → supply a name (e.g. ci-deploy) and, if the modal exposes them, abilities → submit. The returned plaintext token is displayed once in the response/notification. Copy it immediately into your secret store; it cannot be retrieved again.
Treat this as an admin-only convenience layer on top of $user->createToken(). If the modal doesn't expose what you need on day one, don't fight it — the underlying Sanctum API is one line.
Least-privilege abilities per action. Sanctum abilities are a simple string array. The most useful pattern is to define a small set of named ability bundles in config (or an enum) and have the Nova action pull from those rather than free-text:
// config/sanctum-tokens.php (adjust to whatever the package publishes)
'abilities' => [
'read:api' => 'Read API',
'write:api' => 'Write API',
'ci:deploy' => 'CI deploy',
],
Then select via a Nova MultiSelect in the action's fields(). This avoids the classic mistake of admin-created tokens getting ['*'] and quietly becoming root credentials.
Pair with a viewer, not just a creator. The package creates tokens; it usually doesn't give you a management UI. A common day-to-day pattern is to add a HasMany relation in Nova for tokens (Sanctum's PersonalAccessToken model) on the same resource so admins can see existing tokens and revoke them. Sanctum exposes $user->tokens() out of the box; wrap it:
public function tokens(NovaRequest $request)
{
return $this->hasMany(TokenResource::class, 'tokenable_id')
->where('tokenable_type', User::class);
}
Note the tokenable_type filter — Sanctum is polymorphic, so without it you'll surface tokens belonging to other tokenable models.
Wire it into onboarding, not just emergencies. The realistic workflow is: create the user in Nova → immediately trigger the token action from the user detail page → deliver token through a password-manager link or one-time vault. Treat Nova as the provisioning surface and keep the plaintext out of Slack and email.
Scripted / repeatable setup. For anything you'll do more than twice (creating a CI token per new environment), don't click — call the same underlying API in a Nova command or seeder so it's auditable:
$token = $user->createToken('ci-deploy', ['ci:deploy']);
The Nova action is a thin wrapper over this; reach for it only when a human is in the loop.
Integration tip — token expiry. Sanctum's expiration config (config/sanctum.php) governs all tokens globally. If you want per-token expiry from the Nova modal, the action needs to set expires_at on the model after creation. Check the package's fields; if it doesn't support it, add the column in your own wrapper action rather than forking.
The plaintext token is shown exactly once — by design. The package returns it in the action's response. If the notification dismisses before the admin copies it, the token is dead weight and must be revoked and reissued. Design your admin workflow around copy-then-confirm; don't expect to retrieve it later.
Migrations are a hard prerequisite, and error messages are poor. If you see a SQLSTATE[42S02]: Base table or view not found: personal_access_tokens, run php artisan migrate — Sanctum's migration wasn't published. This package will not install it for you.
Nova version drift is the main risk for a package with this star count. Nova's action API changed across 3.x→4.x→5.x (fields(), handleFields(), ActionResponse typing, modal vs. inline). Pin the package version in composer.json and smoke-test in staging after any Nova upgrade. If you hit a fatal error in the action's handle(), the fix is often one or two method signatures — easier to patch locally than wait for a release.
Abilities are not validated against your Sanctum config. Sanctum doesn't enforce that a requested ability is "allowed" — the string array is arbitrary. A typo like read-api instead of read:api results in a token that silently fails every tokenCan() check on the consuming API. Add a rules() on the action fields if the package doesn't, and double-check the string in the created token's abilities column.
Polymorphic tokenable. If your app has more than one authenticatable model (e.g. User and Admin), the action must be registered on the correct resource, and any listing query must filter by tokenable_type. Mixing them up lets an admin mint tokens for the wrong principal.
Revocation is manual. There's no "revoke" affordance implied by the package name. Pair it with $user->currentAccessToken()->delete() in a separate Nova action, or expose the tokens relation so admins can delete rows directly. Sanctum's own tokens()->delete() is fine for "log out everywhere," but be sure that's what you want before wiring it to a Nova button.
Extension point: override the action class. The cleanest customization for a package this small is to extend the shipped action and override handle(), keeping the fields and UI:
class CreateScopedToken extends \MetasyncSite\SanctumTokens\Actions\CreateToken
{
public function handle(ActionFields $fields, Collection $models)
{
// custom abilities, expiry, logging
return parent::handle($fields, $models);
}
}
Debugging: log inside the action's handle() before calling createToken(). If the modal opens but submission does nothing, it's almost always a Nova field validation failure swallowing the response — dump $fields->toArray() first. If the token is created but the plaintext isn't shown, the response type is wrong for your Nova version (string vs ActionResponse vs. custom JSON response).
Don't use this for end-user self-service. It's an admin tool. A user-facing "create your API key" flow belongs in your own controller where you control rate limiting, abilities, expiry, and what's shown in the response — the Nova action gives you none of that surface for free.
How can I help you explore Laravel packages today?