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.
The page a mail links to
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.