Files
laravelDocScrappy/output/12.x/passwords.md
2025-09-02 15:19:23 +02:00

535 lines
18 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Resetting Passwords
* Introduction
* Configuration
* Driver Prerequisites
* Model Preparation
* Configuring Trusted Hosts
* Routing
* Requesting the Password Reset Link
* Resetting the Password
* Deleting Expired Tokens
* Customization
## Introduction
Most web applications provide a way for users to reset their forgotten
passwords. Rather than forcing you to re-implement this by hand for every
application you create, Laravel provides convenient services for sending
password reset links and secure resetting passwords.
Want to get started fast? Install a Laravel [application starter
kit](/docs/12.x/starter-kits) in a fresh Laravel application. Laravel's
starter kits will take care of scaffolding your entire authentication system,
including resetting forgotten passwords.
### Configuration
Your application's password reset configuration file is stored at
`config/auth.php`. Be sure to review the options available to you in this
file. By default, Laravel is configured to use the `database` password reset
driver.
The password reset `driver` configuration option defines where password reset
data will be stored. Laravel includes two drivers:
* `database` \- password reset data is stored in a relational database.
* `cache` \- password reset data is stored in one of your cache-based stores.
### Driver Prerequisites
#### Database
When using the default `database` driver, a table must be created to store
your application's password reset tokens. Typically, this is included in
Laravel's default `0001_01_01_000000_create_users_table.php` database
migration.
#### Cache
There is also a cache driver available for handling password resets, which
does not require a dedicated database table. Entries are keyed by the user's
email address, so ensure you are not using email addresses as a cache key
elsewhere in your application:
1'passwords' => [
2 'users' => [
3 'driver' => 'cache',
4 'provider' => 'users',
5 'store' => 'passwords', // Optional...
6 'expire' => 60,
7 'throttle' => 60,
8 ],
9],
'passwords' => [
'users' => [
'driver' => 'cache',
'provider' => 'users',
'store' => 'passwords', // Optional...
'expire' => 60,
'throttle' => 60,
],
],
To prevent a call to `artisan cache:clear` from flushing your password reset
data, you can optionally specify a separate cache store with the `store`
configuration key. The value should correspond to a store configured in your
`config/cache.php` configuration value.
### Model Preparation
Before using the password reset features of Laravel, your application's
`App\Models\User` model must use the `Illuminate\Notifications\Notifiable`
trait. Typically, this trait is already included on the default
`App\Models\User` model that is created with new Laravel applications.
Next, verify that your `App\Models\User` model implements the
`Illuminate\Contracts\Auth\CanResetPassword` contract. The `App\Models\User`
model included with the framework already implements this interface, and uses
the `Illuminate\Auth\Passwords\CanResetPassword` trait to include the methods
needed to implement the interface.
### Configuring Trusted Hosts
By default, Laravel will respond to all requests it receives regardless of the
content of the HTTP request's `Host` header. In addition, the `Host` header's
value will be used when generating absolute URLs to your application during a
web request.
Typically, you should configure your web server, such as Nginx or Apache, to
only send requests to your application that match a given hostname. However,
if you do not have the ability to customize your web server directly and need
to instruct Laravel to only respond to certain hostnames, you may do so by
using the `trustHosts` middleware method in your application's
`bootstrap/app.php` file. This is particularly important when your application
offers password reset functionality.
To learn more about this middleware method, please consult the [TrustHosts
middleware documentation](/docs/12.x/requests#configuring-trusted-hosts).
## Routing
To properly implement support for allowing users to reset their passwords, we
will need to define several routes. First, we will need a pair of routes to
handle allowing the user to request a password reset link via their email
address. Second, we will need a pair of routes to handle actually resetting
the password once the user visits the password reset link that is emailed to
them and completes the password reset form.
### Requesting the Password Reset Link
#### The Password Reset Link Request Form
First, we will define the routes that are needed to request password reset
links. To get started, we will define a route that returns a view with the
password reset link request form:
1Route::get('/forgot-password', function () {
2 return view('auth.forgot-password');
3})->middleware('guest')->name('password.request');
Route::get('/forgot-password', function () {
return view('auth.forgot-password');
})->middleware('guest')->name('password.request');
The view that is returned by this route should have a form containing an
`email` field, which will allow the user to request a password reset link for
a given email address.
#### Handling the Form Submission
Next, we will define a route that handles the form submission request from the
"forgot password" view. This route will be responsible for validating the
email address and sending the password reset request to the corresponding
user:
1use Illuminate\Http\Request;
2use Illuminate\Support\Facades\Password;
3 
4Route::post('/forgot-password', function (Request $request) {
5 $request->validate(['email' => 'required|email']);
6 
7 $status = Password::sendResetLink(
8 $request->only('email')
9 );
10 
11 return $status === Password::ResetLinkSent
12 ? back()->with(['status' => __($status)])
13 : back()->withErrors(['email' => __($status)]);
14})->middleware('guest')->name('password.email');
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
Route::post('/forgot-password', function (Request $request) {
$request->validate(['email' => 'required|email']);
$status = Password::sendResetLink(
$request->only('email')
);
return $status === Password::ResetLinkSent
? back()->with(['status' => __($status)])
: back()->withErrors(['email' => __($status)]);
})->middleware('guest')->name('password.email');
Before moving on, let's examine this route in more detail. First, the
request's `email` attribute is validated. Next, we will use Laravel's built-in
"password broker" (via the `Password` facade) to send a password reset link to
the user. The password broker will take care of retrieving the user by the
given field (in this case, the email address) and sending the user a password
reset link via Laravel's built-in [notification
system](/docs/12.x/notifications).
The `sendResetLink` method returns a "status" slug. This status may be
translated using Laravel's [localization](/docs/12.x/localization) helpers in
order to display a user-friendly message to the user regarding the status of
their request. The translation of the password reset status is determined by
your application's `lang/{lang}/passwords.php` language file. An entry for
each possible value of the status slug is located within the `passwords`
language file.
By default, the Laravel application skeleton does not include the `lang`
directory. If you would like to customize Laravel's language files, you may
publish them via the `lang:publish` Artisan command.
You may be wondering how Laravel knows how to retrieve the user record from
your application's database when calling the `Password` facade's
`sendResetLink` method. The Laravel password broker utilizes your
authentication system's "user providers" to retrieve database records. The
user provider used by the password broker is configured within the `passwords`
configuration array of your `config/auth.php` configuration file. To learn
more about writing custom user providers, consult the [authentication
documentation](/docs/12.x/authentication#adding-custom-user-providers).
When manually implementing password resets, you are required to define the
contents of the views and routes yourself. If you would like scaffolding that
includes all necessary authentication and verification logic, check out the
[Laravel application starter kits](/docs/12.x/starter-kits).
### Resetting the Password
#### The Password Reset Form
Next, we will define the routes necessary to actually reset the password once
the user clicks on the password reset link that has been emailed to them and
provides a new password. First, let's define the route that will display the
reset password form that is displayed when the user clicks the reset password
link. This route will receive a `token` parameter that we will use later to
verify the password reset request:
1Route::get('/reset-password/{token}', function (string $token) {
2 return view('auth.reset-password', ['token' => $token]);
3})->middleware('guest')->name('password.reset');
Route::get('/reset-password/{token}', function (string $token) {
return view('auth.reset-password', ['token' => $token]);
})->middleware('guest')->name('password.reset');
The view that is returned by this route should display a form containing an
`email` field, a `password` field, a `password_confirmation` field, and a
hidden `token` field, which should contain the value of the secret `$token`
received by our route.
#### Handling the Form Submission
Of course, we need to define a route to actually handle the password reset
form submission. This route will be responsible for validating the incoming
request and updating the user's password in the database:
1use App\Models\User;
2use Illuminate\Auth\Events\PasswordReset;
3use Illuminate\Http\Request;
4use Illuminate\Support\Facades\Hash;
5use Illuminate\Support\Facades\Password;
6use Illuminate\Support\Str;
7 
8Route::post('/reset-password', function (Request $request) {
9 $request->validate([
10 'token' => 'required',
11 'email' => 'required|email',
12 'password' => 'required|min:8|confirmed',
13 ]);
14 
15 $status = Password::reset(
16 $request->only('email', 'password', 'password_confirmation', 'token'),
17 function (User $user, string $password) {
18 $user->forceFill([
19 'password' => Hash::make($password)
20 ])->setRememberToken(Str::random(60));
21 
22 $user->save();
23 
24 event(new PasswordReset($user));
25 }
26 );
27 
28 return $status === Password::PasswordReset
29 ? redirect()->route('login')->with('status', __($status))
30 : back()->withErrors(['email' => [__($status)]]);
31})->middleware('guest')->name('password.update');
use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
Route::post('/reset-password', function (Request $request) {
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|min:8|confirmed',
]);
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function (User $user, string $password) {
$user->forceFill([
'password' => Hash::make($password)
])->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
}
);
return $status === Password::PasswordReset
? redirect()->route('login')->with('status', __($status))
: back()->withErrors(['email' => [__($status)]]);
})->middleware('guest')->name('password.update');
Before moving on, let's examine this route in more detail. First, the
request's `token`, `email`, and `password` attributes are validated. Next, we
will use Laravel's built-in "password broker" (via the `Password` facade) to
validate the password reset request credentials.
If the token, email address, and password given to the password broker are
valid, the closure passed to the `reset` method will be invoked. Within this
closure, which receives the user instance and the plain-text password provided
to the password reset form, we may update the user's password in the database.
The `reset` method returns a "status" slug. This status may be translated
using Laravel's [localization](/docs/12.x/localization) helpers in order to
display a user-friendly message to the user regarding the status of their
request. The translation of the password reset status is determined by your
application's `lang/{lang}/passwords.php` language file. An entry for each
possible value of the status slug is located within the `passwords` language
file. If your application does not contain a `lang` directory, you may create
it using the `lang:publish` Artisan command.
Before moving on, you may be wondering how Laravel knows how to retrieve the
user record from your application's database when calling the `Password`
facade's `reset` method. The Laravel password broker utilizes your
authentication system's "user providers" to retrieve database records. The
user provider used by the password broker is configured within the `passwords`
configuration array of your `config/auth.php` configuration file. To learn
more about writing custom user providers, consult the [authentication
documentation](/docs/12.x/authentication#adding-custom-user-providers).
## Deleting Expired Tokens
If you are using the `database` driver, password reset tokens that have
expired will still be present within your database. However, you may easily
delete these records using the `auth:clear-resets` Artisan command:
1php artisan auth:clear-resets
php artisan auth:clear-resets
If you would like to automate this process, consider adding the command to
your application's [scheduler](/docs/12.x/scheduling):
1use Illuminate\Support\Facades\Schedule;
2 
3Schedule::command('auth:clear-resets')->everyFifteenMinutes();
use Illuminate\Support\Facades\Schedule;
Schedule::command('auth:clear-resets')->everyFifteenMinutes();
## Customization
#### Reset Link Customization
You may customize the password reset link URL using the `createUrlUsing`
method provided by the `ResetPassword` notification class. This method accepts
a closure which receives the user instance that is receiving the notification
as well as the password reset link token. Typically, you should call this
method from the `boot` method of your application's `AppServiceProvider`:
1use App\Models\User;
2use Illuminate\Auth\Notifications\ResetPassword;
3 
4/**
5 * Bootstrap any application services.
6 */
7public function boot(): void
8{
9 ResetPassword::createUrlUsing(function (User $user, string $token) {
10 return 'https://example.com/reset-password?token='.$token;
11 });
12}
use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
ResetPassword::createUrlUsing(function (User $user, string $token) {
return 'https://example.com/reset-password?token='.$token;
});
}
#### Reset Email Customization
You may easily modify the notification class used to send the password reset
link to the user. To get started, override the `sendPasswordResetNotification`
method on your `App\Models\User` model. Within this method, you may send the
notification using any [notification class](/docs/12.x/notifications) of your
own creation. The password reset `$token` is the first argument received by
the method. You may use this `$token` to build the password reset URL of your
choice and send your notification to the user:
1use App\Notifications\ResetPasswordNotification;
2 
3/**
4 * Send a password reset notification to the user.
5 *
6 * @param string $token
7 */
8public function sendPasswordResetNotification($token): void
9{
10 $url = 'https://example.com/reset-password?token='.$token;
11 
12 $this->notify(new ResetPasswordNotification($url));
13}
use App\Notifications\ResetPasswordNotification;
/**
* Send a password reset notification to the user.
*
* @param string $token
*/
public function sendPasswordResetNotification($token): void
{
$url = 'https://example.com/reset-password?token='.$token;
$this->notify(new ResetPasswordNotification($url));
}