Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save amandiobm/f5e5cab3241f2fac0a50c0841819b815 to your computer and use it in GitHub Desktop.
Save amandiobm/f5e5cab3241f2fac0a50c0841819b815 to your computer and use it in GitHub Desktop.
Laravel: Fix password reset (User email not sent)

Here's how to overcome this common gotcha: The default password reset system not working out of the box with Laravel 5.x (as you're not sent the user's password), without having to alter altering vendor/core. Here's how to make it work as you'd expect it to without changing any vendor files.

1. Create own notification

Firstly create a new notification for your app:

php artisan make:notification ResetPassword

Then open the newly created file: app\Notifications\ResetPassword.php and make the following changes:

Add public $token; to the beginning of the class (ie. after use Queueable).

Add $this->token = $token; to the body of your __construct() method.

Add $token as parameter to the __construct() method (so it reads __construct($token)).

Add the following to the body of your toMail() method (replacing what's there by default):

        return (new MailMessage)
            ->line('You are receiving this email because we received a password reset request for your account.')
            ->action('Reset Password', url(config('app.url').route('password.reset', [$this->token, $notifiable->email], false)))
            ->line('If you did not request a password reset, no further action is required.');

What you've done is create a copy of the original vendor/core version of the ResetPassword notification (found in /vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php). This allows you to make customisations to it without changing the core Laravel files.

(One difference we've made is adding $notifiable->email to the body of the email.)

2. Point to your notification

Now we need to tell Laravel to call our notification instead of the one found in the CanResetPassword trait. To do this, just edit your App/User.php model:

Add use App\Notifications\ResetPassword; to the top of the file (ie. a link to the notification you just created) and then add a new method:

    public function sendPasswordResetNotification($token)
    {
        $this->notify(new ResetPassword($token));
    }

3. Update your routes

Finally we need to update our routes to include the new {email} parameter:

Route::get('/password/reset/{token}/{email}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');

Now if the user fills in the /password/reset form, they will be sent your notification, with the additional email parameter.

This now works perfectly!

Additional: Handle errors

You can improve on the above by adding a bit of error handling. To do this, just pass the email to your form, to handle things if there's a problem:

Add the following method to Auth/ForgotPasswordController.php:

    protected function sendResetLinkFailedResponse(Request $request, $response)
    {
        return back()->withErrors(
            ['email' => trans($response)]
        )->withInput($request->only('email'));
    }

And then place the following at the top: use Illuminate\Http\Request;.

And you're done!

Additional: Finesse the UX

If you want, I'd also recommend modifying the semantic HTML in your views (regardless of your design). Go to resources/views/auth/passwords/reset.blade.php and remove the autofocus attribute from the email input element, and add readonly. (I move the autofocus to the first password input element myself.)

Additional: Encrypt the email address in the URL

You can still tidy things up a bit more by encrypting the email in the URL. This isn't for security, it's to make it look prettier (so to speak) and make it less likely for the user to mess with the URL and break something.

To do this, just go to the notification we created in step 1 and change $notifiable->email to encrypt($notifiable->email).

Then go to app/Http/Controllers/Auth/ResetPasswordController.php and add the following method:

    public function showResetForm(Request $request, $token = null)
    {
        return view('auth.passwords.reset')->with(
            ['token' => $token, 'email' => decrypt($request->email)]
        );
    }

Don't forget to place use Illuminate\Http\Request; at the top, too.

And you're done! (Again.)


I've tested all this fully, and it works perfectly, but if you have an issue, let me know.

Good luck!

@HOuter
Copy link

HOuter commented Feb 18, 2020

Hello,

I have tried different ports throughout as suggested by MailTrap though cannot get it to work!

reset blade php
email blade php
ResetPassword php

user php - 1
user php - 2

web php - 1
web php - 2
web php - 3

Here are the details of .env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=6b7357e96c5f2b
MAIL_PASSWORD=cdb579249cd412
MAIL_ENCRYPTION=tls

@amandiobm
Copy link
Author

Hey @HOuter, Let's fix this. Tell me what you are trying to achieve

@HOuter
Copy link

HOuter commented Feb 19, 2020

Please see the relevant pages sent for password-reset, I so need your help.
Tried everything though cannot get it to work in local environment, later today I will endeavour to get the site up through my shared hosting at HostGator. Apart from the password reset all else is finished for the site.

@HOuter
Copy link

HOuter commented Feb 20, 2020

My purpose is to just have an available 'Password Reset' option for the website users with all the pages associated working.

Please see the page locations to assist with this issue ... do I have them correctly placed?
DMD - information structure

Helen.

@amandiobm
Copy link
Author

@HOuter, add me on twitter. lets chat

@HOuter
Copy link

HOuter commented Feb 20, 2020

Have just changed the pages architecture... needs to be like this to display '/password/reset'.
DMD - information structure

Looking for you on Twitter.

@HOuter
Copy link

HOuter commented Feb 20, 2020

Hello, I have a problem with not being able to translate your message to English.
Message says 'This page could not be translated'.

@HOuter
Copy link

HOuter commented Feb 20, 2020

I have attempted to change language of msg though it is still not happening.

@HOuter
Copy link

HOuter commented Feb 20, 2020

Well I guess this is not working... far too many tweets coming in and nothing to do with my issue!

@amandiobm
Copy link
Author

@HOuter, I didn't receive any notifications from twitter. My username @amandiozyxel.

Send me yours, we will fix this.

@HOuter
Copy link

HOuter commented Feb 21, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment