laravel/fortify
Frontend-agnostic authentication backend for Laravel. Provides endpoints and services for registration, login, password reset, email verification, and two-factor authentication. Used by Laravel Starter Kits; you bring the UI (Blade, Inertia, SPA, etc.).
Installation:
composer require laravel/fortify
Publish the configuration and migrations:
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"
php artisan migrate
Configure Auth:
In config/auth.php, set the default guard to web (or your preferred guard):
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
Register Fortify:
Add Fortify to your AppServiceProvider's boot() method:
use Laravel\Fortify\Fortify;
public function boot()
{
Fortify::createUsersUsing(app(\Illuminate\Contracts\Auth\Registrar::class));
}
First Use Case:
Use the Login controller to handle authentication:
use Laravel\Fortify\Http\Controllers\AuthenticatedSessionController;
Route::post('/login', [AuthenticatedSessionController::class, 'store']);
app/Http/Controllers/AuthenticatedSessionController.php (login/logout)app/Http/Requests/AuthenticatedSessionRequest.php (validation rules)app/Http/Middleware/EnsureEmailIsVerified.php (email verification)resources/views/auth/ (if using Blade; Fortify is frontend-agnostic)Login/Logout:
Use AuthenticatedSessionController for handling login/logout requests. Fortify automatically:
AttemptToAuthenticate.redirectIf() logic (e.g., after login).Example route:
Route::post('/login', [AuthenticatedSessionController::class, 'store'])
->middleware('throttle:5,1'); // Rate limiting
Password Confirmation:
Use Confirmable trait or ConfirmPasswordController for password confirmation prompts:
Route::post('/user/confirm-password', [ConfirmPasswordController::class, 'store']);
User Creation:
Extend CreateNewUser to customize registration logic:
use Laravel\Fortify\Actions\CreateNewUser;
class CustomCreateNewUser extends CreateNewUser
{
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
// Custom fields
]);
}
}
Register it in FortifyServiceProvider:
Fortify::createUsersUsing(CustomCreateNewUser::class);
Email Verification:
Use VerifyEmailController and EnsureEmailIsVerified middleware:
Route::get('/email/verify', [VerifyEmailController::class, 'show'])
->middleware('auth')
->name('verification.notice');
Route::post('/email/verify', [VerifyEmailController::class, 'store'])
->middleware(['auth', 'signed', 'throttle:6,1']);
ResetPasswordController for email-based resets:
Route::post('/forgot-password', [ForgotPasswordController::class, 'store']);
Route::post('/reset-password', [NewPasswordController::class, 'store']);
Customize the ForgotPassword action to send emails:
use Laravel\Fortify\Actions\ForgotPassword;
class CustomForgotPassword extends ForgotPassword
{
public function sendResetLinkRequest()
{
$this->user->sendPasswordResetNotification($this->token);
}
}
Enable 2FA:
Use EnableTwoFactorAuthentication and TwoFactorAuthenticatedSessionController:
Route::post('/user/two-factor-authentication', [EnableTwoFactorAuthentication::class])
->middleware('auth');
Add 2FA recovery codes:
Route::post('/user/two-factor-recovery-codes', [RecoveryCodes::class])
->middleware('auth');
Session Handling:
Use InteractsWithTwoFactorState trait to manage 2FA state across requests:
use Laravel\Fortify\Features\TwoFactorAuthentication\InteractsWithTwoFactorState;
class CustomController
{
use InteractsWithTwoFactorState;
}
FortifyServiceProvider:
Fortify::enablePasskeys();
Use PasskeyLoginController and PasskeyRegistrationController:
Route::post('/passkey/register', [PasskeyRegistrationController::class, 'store']);
Route::post('/passkey/login', [PasskeyLoginController::class, 'store']);
Override validation rules in AuthenticatedSessionRequest, CreateNewUserRequest, etc.:
use Illuminate\Validation\Rules;
public function rules()
{
return [
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['required', 'string', Rules\Password::min(8)],
];
}
Use Fortify’s built-in middleware:
EnsureEmailIsVerified: Redirect unverified users.RedirectIfAuthenticated: Protect routes during registration/login.TwoFactorAuthenticatable: Verify 2FA status.Example:
Route::get('/dashboard', function () {
// ...
})->middleware(['auth', 'verified', 'two-factor']);
Listen to Fortify events (e.g., Registered, PasswordReset) in EventServiceProvider:
protected $listen = [
\Laravel\Fortify\Events\Registered::class => [
\App\Listeners\LogRegisteredUser::class,
],
];
Use Fortify facade to test authentication:
use Laravel\Fortify\Fortify;
public function test_login()
{
$user = User::factory()->create();
$response = $this->post('/login', [
'email' => $user->email,
'password' => 'password',
]);
$this->assertAuthenticated();
}
For SPAs, configure Sanctum in FortifyServiceProvider:
Fortify::createUsersUsing()->sanctum();
Use Sanctum middleware for API routes:
Route::middleware(['auth:sanctum', 'verified'])->get('/user', function () {
return response()->json(['user' => auth()->user()]);
});
Session Regeneration:
Fortify::regenerateSessionsOnLogin(false);
2FA State Management:
InteractsWithTwoFactorState trait must be used consistently across requests to avoid state mismatches.Password Reset Tokens:
ForgotPassword:
public function createToken()
{
return Str::random(64);
}
Passkey Compatibility:
Middleware Conflicts:
RedirectIfAuthenticated may conflict with custom middleware. Use unless:
Route::get('/login', function () {})->middleware('guest');
Email Verification:
VerifyEmail:
public function createToken()
{
return Str::random(64);
}
signed middleware to validate tokens.Rate Limiting:
RouteServiceProvider:
Route::fallback(function () {
return response()->json(['message' => 'Not Found'], 4
How can I help you explore Laravel packages today?