Throttling and the switch
Register the API's routes through the package:
// routes/api.php
use Illuminate\Support\Facades\Route;
use Pushery\SanctumHardening\SanctumHardening;
SanctumHardening::routes(function () {
Route::get('/orders', fn () => ['orders' => []]);
});
The routes are registered under routes.prefix, api by default, behind routes.middleware,
api and auth:sanctum by default, and behind the package's limiter. routes.middleware takes a
list or a single middleware as a string. A setting that names none, an empty list for instance,
keeps api and auth:sanctum, so the routes never run without the token guard by accident.
Two stages
Each token has its own limit, throttle.per_token requests a minute, and each user has one over all
of their tokens, throttle.per_user. Without the second, a user gets past every limit of a token by
minting another one. A request over either is answered with 429 as a problem document
(RFC 9457), with the Retry-After header the limiter computed:
{
"type": "about:blank",
"title": "Too Many Requests",
"status": 429,
"detail": "Too many requests. Another one can be sent once the time in the Retry-After header has passed.",
"instance": "/api/orders"
}
A request authenticated by the session rather than a token counts as one token of its user. A request nobody is signed in for is counted by its address, kept as a keyed hash, because a rate limiter's key is a cache key and error trackers record cache keys.
The switch
SANCTUM_HARDENING_ENABLED=false switches the API off. SanctumHardening::routes() then
registers nothing, so the routes do not exist: a request meets no 403 from a route that refuses
but the 404 of a route that is not there, and route:list names none. Minting is not affected.
The last use of a token
Sanctum writes last_used_at on every request a token makes, so a busy token turns each request
into a write on the same row. The package lets that write through once every last_used_at.every
seconds, a minute by default. A save of a token that changes anything else goes through as it is.