Introduction
Laravel
Fortify is a frontend agnostic authentication
backend implementation for Laravel. Fortify registers
the routes and controllers needed to implement all of
Laravel's authentication features, including login,
registration, password reset, email verification, and
more. After installing Fortify, you may run the
route:list
Artisan command to see the
routes that Fortify has registered.
Since Fortify does not provide its own user interface, it is meant to be paired with your own user interface which makes requests to the routes it registers. We will discuss exactly how to make requests to these routes in the remainder of this documentation.
Note:
Remember, Fortify is a package that is meant to give you a head start implementing Laravel's authentication features. You are not required to use it. You are always free to manually interact with Laravel's authentication services by following the documentation available in the authentication, password reset, and email verification documentation.
What is Fortify?
As mentioned previously, Laravel Fortify is a frontend agnostic authentication backend implementation for Laravel. Fortify registers the routes and controllers needed to implement all of Laravel's authentication features, including login, registration, password reset, email verification, and more.
You are not required to use Fortify in order to use Laravel's authentication features. You are always free to manually interact with Laravel's authentication services by following the documentation available in the authentication, password reset, and email verification documentation.
If you are new to Laravel, you may wish to explore the Laravel Breeze application starter kit before attempting to use Laravel Fortify. Laravel Breeze provides an authentication scaffolding for your application that includes a user interface built with Tailwind CSS. Unlike Fortify, Breeze publishes its routes and controllers directly into your application. This allows you to study and get comfortable with Laravel's authentication features before allowing Laravel Fortify to implement these features for you.
Laravel Fortify essentially takes the routes and controllers of Laravel Breeze and offers them as a package that does not include a user interface. This allows you to still quickly scaffold the backend implementation of your application's authentication layer without being tied to any particular frontend opinions.
When Should I Use Fortify?
You may be wondering when it is appropriate to use Laravel Fortify. First, if you are using one of Laravel's application starter kits, you do not need to install Laravel Fortify since all of Laravel's application starter kits already provide a full authentication implementation.
If you are not using an application starter kit and your application needs authentication features, you have two options: manually implement your application's authentication features or use Laravel Fortify to provide the backend implementation of these features.
If you choose to install Fortify, your user interface will make requests to Fortify's authentication routes that are detailed in this documentation in order to authenticate and register users.
If you choose to manually interact with Laravel's authentication services instead of using Fortify, you may do so by following the documentation available in the authentication, password reset, and email verification documentation.
Laravel Fortify and Laravel Sanctum
Some developers become confused regarding the difference between Laravel Sanctum and Laravel Fortify. Because the two packages solve two different but related problems, Laravel Fortify and Laravel Sanctum are not mutually exclusive or competing packages.
Laravel Sanctum is only concerned with managing API tokens and authenticating existing users using session cookies or tokens. Sanctum does not provide any routes that handle user registration, password reset, etc.
If you are attempting to manually build the authentication layer for an application that offers an API or serves as the backend for a single-page application, it is entirely possible that you will utilize both Laravel Fortify (for user registration, password reset, etc.) and Laravel Sanctum (API token management, session authentication).
Installation
To get started, install Fortify using the Composer package manager:
composer require laravel/fortify
Next, publish Fortify's resources using the
vendor:publish
command:
php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"
This command will publish Fortify's actions to your
app/Actions
directory, which will be
created if it does not exist. In addition, the
FortifyServiceProvider
, configuration file,
and all necessary database migrations will be
published.
Next, you should migrate your database:
php artisan migrate
The Fortify Service Provider
The vendor:publish
command discussed above
will also publish the
App\Providers\FortifyServiceProvider
class.
You should ensure this class is registered within the
providers
array of your application's
config/app.php
configuration file.
The Fortify service provider registers the actions that Fortify published and instructs Fortify to use them when their respective tasks are executed by Fortify.
Fortify Features
The fortify
configuration file contains a
features
configuration array. This array
defines which backend routes / features Fortify will
expose by default. If you are not using Fortify in
combination with Laravel
Jetstream, we recommend that you only enable the
following features, which are the basic authentication
features provided by most Laravel applications:
'features' => [
Features::registration(),
Features::resetPasswords(),
Features::emailVerification(),
],
Disabling Views
By default, Fortify defines routes that are intended to
return views, such as a login screen or registration
screen. However, if you are building a JavaScript driven
single-page application, you may not need these routes.
For that reason, you may disable these routes entirely
by setting the views
configuration value
within your application's
config/fortify.php
configuration file to
false
:
'views' => false,
Disabling Views and Password Reset
If you choose to disable Fortify's views and you will be
implementing password reset features for your
application, you should still define a route named
password.reset
that is responsible for
displaying your application's "reset password"
view. This is necessary because Laravel's
Illuminate\Auth\Notifications\ResetPassword
notification will generate the password reset URL via
the password.reset
named route.
Authentication
To get started, we need to instruct Fortify how to return our "login" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an application starter kit.
All of the authentication view's rendering logic may be
customized using the appropriate methods available via
the Laravel\Fortify\Fortify
class.
Typically, you should call this method from the
boot
method of your application's
App\Providers\FortifyServiceProvider
class.
Fortify will take care of defining the
/login
route that returns this view:
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::loginView(function () {
return view('auth.login');
});
// ...
}
Your login template should include a form that makes a
POST request to /login
. The
/login
endpoint expects a string
email
/ username
and a
password
. The name of the email / username
field should match the username
value
within the config/fortify.php
configuration
file. In addition, a boolean remember
field
may be provided to indicate that the user would like to
use the "remember me" functionality provided
by Laravel.
If the login attempt is successful, Fortify will redirect
you to the URI configured via the home
configuration option within your application's
fortify
configuration file. If the login
request was an XHR request, a 200 HTTP response will be
returned.
If the request was not successful, the user will be
redirected back to the login screen and the validation
errors will be available to you via the shared
$errors
Blade
template variable. Or, in the case of an XHR
request, the validation errors will be returned with the
422 HTTP response.
Customizing User Authentication
Fortify will automatically retrieve and authenticate the
user based on the provided credentials and the
authentication guard that is configured for your
application. However, you may sometimes wish to have
full customization over how login credentials are
authenticated and users are retrieved. Thankfully,
Fortify allows you to easily accomplish this using the
Fortify::authenticateUsing
method.
This method accepts a closure which receives the incoming
HTTP request. The closure is responsible for validating
the login credentials attached to the request and
returning the associated user instance. If the
credentials are invalid or no user can be found,
null
or false
should be
returned by the closure. Typically, this method should
be called from the boot
method of your
FortifyServiceProvider
:
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::authenticateUsing(function (Request $request) {
$user = User::where('email', $request->email)->first();
if ($user &&
Hash::check($request->password, $user->password)) {
return $user;
}
});
// ...
}
Authentication Guard
You may customize the authentication guard used by
Fortify within your application's fortify
configuration file. However, you should ensure that the
configured guard is an implementation of
Illuminate\Contracts\Auth\StatefulGuard
. If
you are attempting to use Laravel Fortify to
authenticate an SPA, you should use Laravel's default
web
guard in combination with Laravel
Sanctum.
Customizing the Authentication Pipeline
Laravel Fortify authenticates login requests through a
pipeline of invokable classes. If you would like, you
may define a custom pipeline of classes that login
requests should be piped through. Each class should have
an __invoke
method which receives the
incoming Illuminate\Http\Request
instance
and, like middleware, a
$next
variable that is invoked in order to
pass the request to the next class in the pipeline.
To define your custom pipeline, you may use the
Fortify::authenticateThrough
method. This
method accepts a closure which should return the array
of classes to pipe the login request through. Typically,
this method should be called from the boot
method of your
App\Providers\FortifyServiceProvider
class.
The example below contains the default pipeline definition that you may use as a starting point when making your own modifications:
use Laravel\Fortify\Actions\AttemptToAuthenticate;
use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled;
use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
use Laravel\Fortify\Fortify;
use Illuminate\Http\Request;
Fortify::authenticateThrough(function (Request $request) {
return array_filter([
config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
AttemptToAuthenticate::class,
PrepareAuthenticatedSession::class,
]);
});
Customizing Redirects
If the login attempt is successful, Fortify will redirect
you to the URI configured via the home
configuration option within your application's
fortify
configuration file. If the login
request was an XHR request, a 200 HTTP response will be
returned. After a user logs out of the application, the
user will be redirected to the /
URI.
If you need advanced customization of this behavior, you
may bind implementations of the
LoginResponse
and
LogoutResponse
contracts into the Laravel
service container.
Typically, this should be done within the
register
method of your application's
App\Providers\FortifyServiceProvider
class:
use Laravel\Fortify\Contracts\LogoutResponse;
/**
* Register any application services.
*/
public function register(): void
{
$this->app->instance(LogoutResponse::class, new class implements LogoutResponse {
public function toResponse($request)
{
return redirect('/');
}
});
}
Two Factor Authentication
When Fortify's two factor authentication feature is enabled, the user is required to input a six digit numeric token during the authentication process. This token is generated using a time-based one-time password (TOTP) that can be retrieved from any TOTP compatible mobile authentication application such as Google Authenticator.
Before getting started, you should first ensure that your
application's App\Models\User
model uses
the
Laravel\Fortify\TwoFactorAuthenticatable
trait:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
class User extends Authenticatable
{
use Notifiable, TwoFactorAuthenticatable;
}
Next, you should build a screen within your application where users can manage their two factor authentication settings. This screen should allow the user to enable and disable two factor authentication, as well as regenerate their two factor authentication recovery codes.
By default, the
features
array of thefortify
configuration file instructs Fortify's two factor authentication settings to require password confirmation before modification. Therefore, your application should implement Fortify's password confirmation feature before continuing.
Enabling Two Factor Authentication
To begin enabling two factor authentication, your
application should make a POST request to the
/user/two-factor-authentication
endpoint
defined by Fortify. If the request is successful, the
user will be redirected back to the previous URL and the
status
session variable will be set to
two-factor-authentication-enabled
. You may
detect this status
session variable within
your templates to display the appropriate success
message. If the request was an XHR request,
200
HTTP response will be returned.
After choosing to enable two factor authentication, the user must still "confirm" their two factor authentication configuration by providing a valid two factor authentication code. So, your "success" message should instruct the user that two factor authentication confirmation is still required:
@if (session('status') == 'two-factor-authentication-enabled')
<div class="mb-4 font-medium text-sm">
Please finish configuring two factor authentication below.
</div>
@endif
Next, you should display the two factor authentication QR
code for the user to scan into their authenticator
application. If you are using Blade to render your
application's frontend, you may retrieve the QR code SVG
using the twoFactorQrCodeSvg
method
available on the user instance:
$request->user()->twoFactorQrCodeSvg();
If you are building a JavaScript powered frontend, you
may make an XHR GET request to the
/user/two-factor-qr-code
endpoint to
retrieve the user's two factor authentication QR code.
This endpoint will return a JSON object containing an
svg
key.
Confirming Two Factor Authentication
In addition to displaying the user's two factor
authentication QR code, you should provide a text input
where the user can supply a valid authentication code to
"confirm" their two factor authentication
configuration. This code should be provided to the
Laravel application via a POST request to the
/user/confirmed-two-factor-authentication
endpoint defined by Fortify.
If the request is successful, the user will be redirected
back to the previous URL and the status
session variable will be set to
two-factor-authentication-confirmed
:
@if (session('status') == 'two-factor-authentication-confirmed')
<div class="mb-4 font-medium text-sm">
Two factor authentication confirmed and enabled successfully.
</div>
@endif
If the request to the two factor authentication
confirmation endpoint was made via an XHR request, a
200
HTTP response will be returned.
Displaying the Recovery Codes
You should also display the user's two factor recovery codes. These recovery codes allow the user to authenticate if they lose access to their mobile device. If you are using Blade to render your application's frontend, you may access the recovery codes via the authenticated user instance:
(array) $request->user()->recoveryCodes()
If you are building a JavaScript powered frontend, you
may make an XHR GET request to the
/user/two-factor-recovery-codes
endpoint.
This endpoint will return a JSON array containing the
user's recovery codes.
To regenerate the user's recovery codes, your application
should make a POST request to the
/user/two-factor-recovery-codes
endpoint.
Authenticating With Two Factor Authentication
During the authentication process, Fortify will
automatically redirect the user to your application's
two factor authentication challenge screen. However, if
your application is making an XHR login request, the
JSON response returned after a successful authentication
attempt will contain a JSON object that has a
two_factor
boolean property. You should
inspect this value to know whether you should redirect
to your application's two factor authentication
challenge screen.
To begin implementing two factor authentication
functionality, we need to instruct Fortify how to return
our two factor authentication challenge view. All of
Fortify's authentication view rendering logic may be
customized using the appropriate methods available via
the Laravel\Fortify\Fortify
class.
Typically, you should call this method from the
boot
method of your application's
App\Providers\FortifyServiceProvider
class:
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::twoFactorChallengeView(function () {
return view('auth.two-factor-challenge');
});
// ...
}
Fortify will take care of defining the
/two-factor-challenge
route that returns
this view. Your two-factor-challenge
template should include a form that makes a POST request
to the /two-factor-challenge
endpoint. The
/two-factor-challenge
action expects a
code
field that contains a valid TOTP token
or a recovery_code
field that contains one
of the user's recovery codes.
If the login attempt is successful, Fortify will redirect
the user to the URI configured via the home
configuration option within your application's
fortify
configuration file. If the login
request was an XHR request, a 204 HTTP response will be
returned.
If the request was not successful, the user will be
redirected back to the two factor challenge screen and
the validation errors will be available to you via the
shared $errors
Blade
template variable. Or, in the case of an XHR
request, the validation errors will be returned with a
422 HTTP response.
Disabling Two Factor Authentication
To disable two factor authentication, your application
should make a DELETE request to the
/user/two-factor-authentication
endpoint.
Remember, Fortify's two factor authentication endpoints
require password
confirmation prior to being called.
Registration
To begin implementing our application's registration functionality, we need to instruct Fortify how to return our "register" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an application starter kit.
All of Fortify's view rendering logic may be customized
using the appropriate methods available via the
Laravel\Fortify\Fortify
class. Typically,
you should call this method from the boot
method of your
App\Providers\FortifyServiceProvider
class:
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::registerView(function () {
return view('auth.register');
});
// ...
}
Fortify will take care of defining the
/register
route that returns this view.
Your register
template should include a
form that makes a POST request to the
/register
endpoint defined by Fortify.
The /register
endpoint expects a string
name
, string email address / username,
password
, and
password_confirmation
fields. The name of
the email / username field should match the
username
configuration value defined within
your application's fortify
configuration
file.
If the registration attempt is successful, Fortify will
redirect the user to the URI configured via the
home
configuration option within your
application's fortify
configuration file.
If the request was an XHR request, a 201 HTTP response
will be returned.
If the request was not successful, the user will be
redirected back to the registration screen and the
validation errors will be available to you via the
shared $errors
Blade
template variable. Or, in the case of an XHR
request, the validation errors will be returned with a
422 HTTP response.
Customizing Registration
The user validation and creation process may be
customized by modifying the
App\Actions\Fortify\CreateNewUser
action
that was generated when you installed Laravel
Fortify.
Password Reset
Requesting a Password Reset Link
To begin implementing our application's password reset functionality, we need to instruct Fortify how to return our "forgot password" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an application starter kit.
All of Fortify's view rendering logic may be customized
using the appropriate methods available via the
Laravel\Fortify\Fortify
class. Typically,
you should call this method from the boot
method of your application's
App\Providers\FortifyServiceProvider
class:
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::requestPasswordResetLinkView(function () {
return view('auth.forgot-password');
});
// ...
}
Fortify will take care of defining the
/forgot-password
endpoint that returns this
view. Your forgot-password
template should
include a form that makes a POST request to the
/forgot-password
endpoint.
The /forgot-password
endpoint expects a
string email
field. The name of this field
/ database column should match the email
configuration value within your application's
fortify
configuration file.
Handling the Password Reset Link Request Response
If the password reset link request was successful,
Fortify will redirect the user back to the
/forgot-password
endpoint and send an email
to the user with a secure link they can use to reset
their password. If the request was an XHR request, a 200
HTTP response will be returned.
After being redirected back to the
/forgot-password
endpoint after a
successful request, the status
session
variable may be used to display the status of the
password reset link request attempt.
The value of the $status
session variable
will match one of the translation strings defined within
your application's passwords
language file. If you
would like to customize this value and have not
published Laravel's language files, you may do so via
the lang:publish
Artisan command:
@if (session('status'))
<div class="mb-4 font-medium text-sm text-green-600">
{{ session('status') }}
</div>
@endif
If the request was not successful, the user will be
redirected back to the request password reset link
screen and the validation errors will be available to
you via the shared $errors
Blade
template variable. Or, in the case of an XHR
request, the validation errors will be returned with a
422 HTTP response.
Resetting the Password
To finish implementing our application's password reset functionality, we need to instruct Fortify how to return our "reset password" view.
All of Fortify's view rendering logic may be customized
using the appropriate methods available via the
Laravel\Fortify\Fortify
class. Typically,
you should call this method from the boot
method of your application's
App\Providers\FortifyServiceProvider
class:
use Laravel\Fortify\Fortify;
use Illuminate\Http\Request;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::resetPasswordView(function (Request $request) {
return view('auth.reset-password', ['request' => $request]);
});
// ...
}
Fortify will take care of defining the route to display
this view. Your reset-password
template
should include a form that makes a POST request to
/reset-password
.
The /reset-password
endpoint expects a
string email
field, a password
field, a password_confirmation
field, and a
hidden field named token
that contains the
value of request()->route('token')
. The
name of the "email" field / database column
should match the email
configuration value
defined within your application's fortify
configuration file.
Handling the Password Reset Response
If the password reset request was successful, Fortify
will redirect back to the /login
route so
that the user can log in with their new password. In
addition, a status
session variable will be
set so that you may display the successful status of the
reset on your login screen:
@if (session('status'))
<div class="mb-4 font-medium text-sm text-green-600">
{{ session('status') }}
</div>
@endif
If the request was an XHR request, a 200 HTTP response will be returned.
If the request was not successful, the user will be
redirected back to the reset password screen and the
validation errors will be available to you via the
shared $errors
Blade
template variable. Or, in the case of an XHR
request, the validation errors will be returned with a
422 HTTP response.
Customizing Password Resets
The password reset process may be customized by modifying
the App\Actions\ResetUserPassword
action
that was generated when you installed Laravel
Fortify.
Email Verification
After registration, you may wish for users to verify
their email address before they continue accessing your
application. To get started, ensure the
emailVerification
feature is enabled in
your fortify
configuration file's
features
array. Next, you should ensure
that your App\Models\User
class implements
the
Illuminate\Contracts\Auth\MustVerifyEmail
interface.
Once these two setup steps have been completed, newly registered users will receive an email prompting them to verify their email address ownership. However, we need to inform Fortify how to display the email verification screen which informs the user that they need to go click the verification link in the email.
All of Fortify's view's rendering logic may be customized
using the appropriate methods available via the
Laravel\Fortify\Fortify
class. Typically,
you should call this method from the boot
method of your application's
App\Providers\FortifyServiceProvider
class:
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::verifyEmailView(function () {
return view('auth.verify-email');
});
// ...
}
Fortify will take care of defining the route that
displays this view when a user is redirected to the
/email/verify
endpoint by Laravel's
built-in verified
middleware.
Your verify-email
template should include an
informational message instructing the user to click the
email verification link that was sent to their email
address.
Resending Email Verification Links
If you wish, you may add a button to your application's
verify-email
template that triggers a POST
request to the
/email/verification-notification
endpoint.
When this endpoint receives a request, a new
verification email link will be emailed to the user,
allowing the user to get a new verification link if the
previous one was accidentally deleted or lost.
If the request to resend the verification link email was
successful, Fortify will redirect the user back to the
/email/verify
endpoint with a
status
session variable, allowing you to
display an informational message to the user informing
them the operation was successful. If the request was an
XHR request, a 202 HTTP response will be returned:
@if (session('status') == 'verification-link-sent')
<div class="mb-4 font-medium text-sm text-green-600">
A new email verification link has been emailed to you!
</div>
@endif
Protecting Routes
To specify that a route or group of routes requires that
the user has verified their email address, you should
attach Laravel's built-in verified
middleware to the route. This middleware is registered
within your application's App\Http\Kernel
class:
Route::get('/dashboard', function () {
// ...
})->middleware(['verified']);
Password Confirmation
While building your application, you may occasionally
have actions that should require the user to confirm
their password before the action is performed.
Typically, these routes are protected by Laravel's
built-in password.confirm
middleware.
To begin implementing password confirmation functionality, we need to instruct Fortify how to return our application's "password confirmation" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an application starter kit.
All of Fortify's view rendering logic may be customized
using the appropriate methods available via the
Laravel\Fortify\Fortify
class. Typically,
you should call this method from the boot
method of your application's
App\Providers\FortifyServiceProvider
class:
use Laravel\Fortify\Fortify;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::confirmPasswordView(function () {
return view('auth.confirm-password');
});
// ...
}
Fortify will take care of defining the
/user/confirm-password
endpoint that
returns this view. Your confirm-password
template should include a form that makes a POST request
to the /user/confirm-password
endpoint. The
/user/confirm-password
endpoint expects a
password
field that contains the user's
current password.
If the password matches the user's current password, Fortify will redirect the user to the route they were attempting to access. If the request was an XHR request, a 201 HTTP response will be returned.
If the request was not successful, the user will be
redirected back to the confirm password screen and the
validation errors will be available to you via the
shared $errors
Blade template variable. Or,
in the case of an XHR request, the validation errors
will be returned with a 422 HTTP response.