Skip to main content

Alerts

Name the page that carries the screen, and schedule the command daily:

// config/sanctum-hardening.php
'alerts' => [
'link' => 'settings.tokens',
'expiring' => ['enabled' => true, 'days' => 7],
'inactive' => ['enabled' => true, 'days' => 90],
],
// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('sanctum-hardening:send-alerts')->daily();

The command says how many mails it sent of each kind, and runs once at a time with --isolated.

Before an expiry​

The holder of a token that expires within expiring.days days, 7 by default, gets a mail with the token's name, the first characters of its secret and the day it expires. Requests that use the token stop working on that day, so the mail is the time to create a new one, or to revoke the old one early if it is no longer needed.

After a silence​

The holder of a token no request has used for inactive.days days, 90 by default, gets a mail with the day it was last used. A token that was never used counts from the day it was created. The last use is the one Sanctum writes to last_used_at, so the recorded requests are not needed for it. A token that has expired gets no such mail.

Once for each occasion​

Each mail goes out once for the same expiry, and once for the same last use. A token that is used again after its mail, and then goes unused for another inactive.days days, gets a new one, and so does a token whose expiry was moved. A token with a reserved ability gets none, because the screen neither lists nor revokes it, and neither does a revoked token. enabled switches either mail off.

link takes a route name or an address. A token due for a mail while no page is named gets none: the command names how many tokens it passed over and fails, so a schedule that reports failed commands shows it.

Who receives a mail​

A mail goes to the token's holder through Laravel's notifications, where the holder receives them: a model with the Notifiable trait. A token whose holder receives none is passed over, and the command says how many. The mail is written in the holder's language where the model implements HasLocalePreference, and in the application's language otherwise. To change the text, publish the translations with --tag=sanctum-hardening-lang and edit the alerts entries.

A token that belongs to a workspace is mailed to whoever the application names. Bind a resolver of your own in a service provider's register():

use Illuminate\Database\Eloquent\Model;
use Pushery\SanctumHardening\Tokens\ResolvesTokenAlerts;

final class WorkspaceTokenAlerts implements ResolvesTokenAlerts
{
public function recipient(Model $token): ?object
{
return $token->tokenable?->owner;
}

public function link(Model $token): ?string
{
return route('workspaces.tokens', $token->tokenable);
}
}

$this->app->bind(ResolvesTokenAlerts::class, WorkspaceTokenAlerts::class);

recipient() returns a notifiable, or null where nobody receives the mail. link() returns the absolute address of the page where the token is revoked, or null where there is none.

sanctum-hardening:prune-prefixes forgets the record of the mails sent about a deleted token, together with its prefix.