joe-404/laravel-auth
Config-driven, drop-in auth for Laravel 12/13: JSON API for registration with OTP/magic-link verification, login, refresh tokens, password reset, Google OAuth, multi-session/device fingerprinting, long-lived API tokens, account status workflows, and referrals.
Every HTTP middleware the package registers, what it does, where to apply it, what it returns on failure, and how to order it. All package middleware is registered automatically by AuthServiceProvider — you do not need to add anything to bootstrap/app.php. Just reference the alias on your routes.
All failure responses use the same JSON envelope as the rest of the package —
{ "success": false, "message": "...", "errors": {} }— resolved through your configuredResponseFormatterContract. Examples below show the default formatter's output.
Three new middleware aliases were registered in v2.7.1. The alias cheat-sheet and per-middleware sections below do not yet list them. Quick reference:
| Alias | Class | What it does | Since |
|---|---|---|---|
auth.require-2fa-enrolled |
EnforceRequired2FA |
When two_factor.required=true, blocks the package's authenticated routes for users who haven't enrolled a 2FA method, returning data.must_enroll_2fa: true. Exempts /me, /logout (+ /logout/all), /password/confirm, /session/clear, and the entire /2fa/* enrollment surface so users can still enroll or log out. No-op when two_factor.required=false (default). |
v2.7.1 |
auth.api-token-stepup |
RequireStepUpForApiTokenCreation |
Gates API-token routes behind a fresh sudo / 2FA step-up when the matching config flag is on. Takes the flag's config path as a parameter so the same class drives multiple gates: auth.api-token-stepup (user POST, reads api_tokens.require_step_up), auth.api-token-stepup:auth_system.api_tokens.require_step_up_for_revoke (user DELETE — v2.7.3), auth.api-token-stepup:auth_system.api_tokens.admin_require_step_up (admin POST/PATCH/DELETE — v2.7.1 POST / v2.7.2 PATCH+DELETE). The flag is read at request time, so route:cache and per-environment config both behave. |
v2.7.1 |
auth.admin-gate |
AdminGate |
Replaces the hard-coded role: middleware on the package's admin route groups. Takes a config section as a parameter (auth.admin-gate:account.status, auth.admin-gate:api_tokens, auth.admin-gate:referral_code) and reads auth_system.<section>.admin_middleware (override) or admin_ability (fallback) at request time. Each pipe-separated token is treated as a role OR a Spatie permission — passes on the first match. Lets you gate by role (super-admin|admin), by permission (users.manage-status), or any mix. |
v2.7.1 (account.status, api_tokens) / v2.7.3 (referral_code) |
The classes live at src/Http/Middleware/EnforceRequired2FA.php, src/Http/Middleware/RequireStepUpForApiTokenCreation.php, and src/Http/Middleware/AdminGate.php. Full per-flag behavior is documented in the root UPGRADING.md.
| Alias | Class | One-liner | Auth required first? |
|---|---|---|---|
auth.device |
DeviceFingerprint |
Parses the device fingerprint onto the request; touches the session row | No |
auth.api-token |
ApiTokenAuth |
Authenticates a third-party auth_at_* token + checks abilities |
No (it is the authenticator) |
auth.no-refresh |
RejectRefreshToken |
Blocks refresh tokens from being used as access tokens | Yes (auth:sanctum) |
auth.verified |
RequireEmailVerified |
Rejects users whose email is unverified | Yes |
auth.active |
RequireActiveAccount |
Rejects disabled/suspended accounts mid-session | Yes |
auth.2fa |
Require2FA |
Step-up: forces a fresh 2FA challenge / password confirm | Yes |
auth.step-up |
RequireStepUp |
Config-driven step-up (password-confirm or 2FA) for sensitive actions | Yes |
auth.feature |
FeatureFlag |
404s a route group unless auth_system.<feature>.enabled is true |
No |
auth.mode |
AuthMode |
403s a route unless auth_system.mode is in an allow-list |
No |
auth.ratelimit |
RateLimitAuth |
Per-IP + per-email throttle keyed on a config entry | No |
role / permission |
Spatie | Role / permission gate (re-aliased by this package) | Yes |
Some package middleware only works after a Laravel/Sanctum built-in has already run. These are framework middleware, not shipped by this package — but the package's routes require them, and so do yours if you reuse the package middleware on your own routes. The package already wires them into its own route groups; this section tells you which ones matter and why.
auth:sanctum — REQUIRED before most package middlewareShips with: Laravel Sanctum (laravel/sanctum, a hard dependency of this package).
Why it's required. auth:sanctum is what actually authenticates the request — it resolves the bearer token or session cookie into $request->user(). Almost every package middleware downstream reads $request->user():
auth.no-refresh inspects $request->user()?->currentAccessToken().auth.verified calls $user->hasVerifiedEmail().auth.active reads the user's account status.auth.2fa needs to know who to challenge.If you put any of these on a route without auth:sanctum in front, $request->user() is null: auth.verified/auth.active silently pass through (they treat "no user" as "nothing to gate"), and auth.2fa returns 401 Unauthenticated. So: always list auth:sanctum first on protected routes.
// ✅ correct — sanctum authenticates, then package middleware gate
Route::middleware(['auth:sanctum', 'auth.verified', 'auth.2fa'])->group(/* … */);
// ❌ wrong — package middleware run with no authenticated user
Route::middleware(['auth.verified', 'auth.2fa'])->group(/* … */);
Route::middleware(['auth.device', 'throttle:api'])->group(function () {
Route::post('login', ...)->middleware('auth.ratelimit:login');
Route::post('2fa/challenge', ...)->middleware('auth.ratelimit:otp_verify');
// …
});
Route::middleware(['auth:sanctum', 'auth.no-refresh', 'auth.verified', 'auth.device'])
->group(function () {
Route::get('me', ...);
Route::delete('trusted-devices/{id}', ...)->middleware('auth.2fa');
// …
});
X-Device-Info — mobile apps send a structured device descriptor.auth_at_.ApiTokenService (existence, not-revoked, not-expired).auth.api-token — any valid token.
auth.api-token:read — token must have the read ability.
401 — "API token required." (missing / wrong prefix), or the typed exception message (revoked, expired), or "Invalid API token." (unexpected error; details are logged, never leaked).
auth_system.two_factor.sudo_ttl_minutes (default 15), pass through.403 with a challenge_token. The client completes POST /auth/2fa/challenge, then retries the original request.auth_system.two_factor.middleware_behavior:
block → 403, step_up: enroll_2fa (client must redirect to enrollment).force_enroll → 403, step_up: enroll_2fa (same signal; intended for a "set up 2FA now" modal).Route::middleware(['auth:sanctum', 'auth.2fa'])->group(function () {
Route::delete('account', ...);
Route::post('billing/cancel', ...);
});
password_confirm (default) — the user must have a fresh sudo window from POST /auth/password/confirm (valid for sudo_ttl_minutes). Works for users with or without 2FA.How can I help you explore Laravel packages today?