Laravel - Custom Password Recovery and Localization
Home / Snippets / PHP / Laravel - Custom Password Recovery and Localization
Nowadays, I’m maintaining five Laravel websites. One of them I built from scratch. It’s super simple.
Today, I implemented a password recovery flow on one of the other four. At first, I thought it would be straightforward, but it turned out to be a bit trickier than expected.
I had to set up a named route (password.reset), create two Blade forms, handle requests and resets, and work on translations. Even with Laravel’s scaffolding, fully customizing the feature took me around 2 hours.
One part that tripped me up was creating a global translation group. After some trial and error, I discovered that using "*" as the group name allows __("Hello!") to be translated without specifying a group. It is not covered in Laraval localization documentation. A small but useful trick!
It was a good reminder that frameworks make things easier, but deep customization still requires attention, research, and patience.
Creating the php classes
Use artisan to create the classes:
php artisan make:notification ResetPasswordController
php artisan make:notification ResetPasswordNotification
class ResetPasswordController extends Controller
{
use SendsPasswordResetEmails; // This trait has some of methods required in the process
//Override if you are not using the defaul view path
public function showLinkRequestForm() {
return view('admin.auth.passwords.email');
}
//Override if you have more the one user provider
protected function broker() {
return Password::broker('admin_users');
}
//Get method for password reset
public function showResetForm(Request $request) {
$token = $request->get('token');
$email = $request->get('email');
return view('admin.auth.passwords.reset', ['token' => $token, 'email' => $email]);
}
// Handle actual password reset
public function reset(Request $request) {
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|min:8|confirmed',
]);
//Password::reset could be used if you want the default
$status = $this->broker()->reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user) use ($request) {
$user->forceFill([
'password' => Hash::make($request->password)
])->save();
}
);
return $status === Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withErrors(['email' => [__($status)]]);
}
}
In order to customize email message you need to override the method sendPasswordResetNotification in you User model.
public function sendPasswordResetNotification($token){
$this->notify(new ResetPasswordNotification($token));
}
The custom notification can be set using the method toMail in ResetPasswordNotification class:
public function toMail($notifiable) {
$url = url(route('password.reset', [
'token' => $this->token,
'email' => $notifiable->email,
], false));
return (new MailMessage)
->subject('Reset Password')
->line('Intro text here...')
->action('Reset Password', $url)
->line('Tuther explain how it works...');
}
Register the routes
Route::get('/forgot-password', [ResetPasswordController::class, 'showLinkRequestForm']);
Route::post('/forgot-password', [ResetPasswordController::class, 'sendResetLinkEmail']);
Route::get('/reset-password', [ResetPasswordController::class, 'showResetForm'])->name("password.reset");
Route::post('/reset-password', [ResetPasswordController::class, 'reset']);
The name in GET /reset-password is important when sending recover password link.
Localization
Edit your AppServiceProvider file.
The following code use Translator addLines method to load the map of key values for the specified locale
public function boot() {
/* ... */
Lang::addLines(require base_path('lang/pt-br/global.php'), 'pt-br');
}
Create the translation file. The * before key is important to tell it is a global group. This is not documented in Laravel reference.
<?php
return [
'*.Hello!' => 'Olá!',
'*.Regards' => 'Atenciosamente',
];
