Home » Code » Password reminders and reset in Laravel 4

Password reminders and reset in Laravel 4

Posted by on September 23rd, 2013

Password reminders and reset in Laravel 4
A couple of weeks ago I looked at how to create registration and authentication functionality in Laravel 4. Registering and authenticating are two of the fundamental features of a social application.

The third crucial component of this user interaction cycle is allowing users to be able to request an email to reset their password. This is one of those features that is so easy to overlook when developing an application, but your users will soon let you know about it if you forget it.

Fortunately Laravel 4 makes setting up this functionality incredibly easy and so this will be our focus for this week’s tutorial.

The remindable interface

If you remember back to Setting up your first Laravel 4 Model, I briefly touched upon the remindable interface. It is this interface that enables Laravel’s reminder functionality to work out of the box.

So before we begin, ensure that your model implements the interface like this:

class User extends Magniloquent implements UserInterface, RemindableInterface {}

How the process works

I’m sure you have reset your password on an online service in the past so you’ll be well aware of how this kind of thing works, but just for clarity, I will talk you through how it works in Laravel.

  1. First a user requests a reminder to be sent to their registered email address.
  2. This action generates a secret token which is stored in the database alongside the timestamp of when it was created.
  3. An email is sent to the user with a link to a form for them to reset their password. The secret token which we generated in the previous step is set as a parameter on the URL.
  4. When the user clicks the link and is taken to the password reset form the token is validated against the record in the database.
  5. If the token is valid, the user is allowed to reset their password

What are we going to need to create?

As you can see from the process above, it is relatively simple to create a system to allow users to reset their password, especially seeing as though Laravel does all of the heavy lifting for us.

However, we are still going to have to create a few things in order for the process to work:

Table migration
We need a way of being able to store the reminder tokens in the database. Polluting the user table wouldn’t be a good idea, so Laravel can automatically generate the migration for the table for you.

We will need a couple of routes to be able to GET the forms and POST the results to.

Password Controller
We are going to need to use a couple of Controller methods to display forms and accept POST requests so it makes sense to keep them all together in the same Controller.

Reset Views
And finally, we need two views. The first one is to display the form to request the reminder email, and the second one is to display the form that accepts the new password.

Creating the table migration

As I mentioned above, Laravel ships with much of this functionality all ready for you to implement. One big time saver is that you can automatically create the migration using the artisan command line interface. This is fantastic because it means you don’t have to think about the schema that you’re going to need.

To create the migration, simply run the following in Terminal:

php artisan auth:reminders

This should create the following migration:


use Illuminate\Database\Migrations\Migration;

class CreatePasswordRemindersTable extends Migration {

   * Run the migrations.
   * @return void
  public function up()
    Schema::create('password_reminders', function($t)

   * Reverse the migrations.
   * @return void
  public function down()


Finally, run the migration:

php artisan migrate

Creating the reminder form

So the first thing we need to do is to create a form that will allow a user to enter her email address to request a reset link.

First, create a new route in your routes.php file:

Route::get('password/reset', array(
  'uses' => 'PasswordController@remind',
  'as' => 'password.remind'

Here I’m simply setting a GET route that is associated with a method on the Controller.

Next, create a new Controller file called PasswordController.php and copy the following code:

class PasswordController extends BaseController {

  public function remind()
    return View::make('password.remind');

As you can see from the method above, all we have to do is to return a View file.

So under your views directory, create a new folder called password and a new view filed called remind.blade.php and copy the following code:

@if (Session::has('error'))
  {{ trans(Session::get('reason')) }}
@elseif (Session::has('success'))
  An email with the password reset has been sent.

{{ Form::open(array('route' => 'password.request')) }}

  <p>{{ Form::label('email', 'Email') }}
  {{ Form::text('email') }}</p>

  <p>{{ Form::submit('Submit') }}</p>

{{ Form::close() }}

If you remember back to my post on Laravel 4 forms the code above should look familiar. Basically the code above will generate a form with an email input field and a submit button. When the form is submitted, it with be POSTed to the password.request route.

The if…else statement above the form will display any errors or a confirmation if the form was been submitted correctly.

Sending the request email

Next we need to set up another route to POST the form to and a method on the Controller to send the email.

Back in your routes.php file, copy the following new route:

Route::post('password/reset', array(
  'uses' => 'PasswordController@request',
  'as' => 'password.request'

Now, in your PasswordController.php file, add the following new method:

public function request()
  $credentials = array('email' => Input::get('email'), 'password' => 'Input::get('password'));

  return Password::remind($credentials);

This super simple method uses Laravel’s input reminder functionality to add the email to the reminder table we created earlier and send the email. You might get an exception saying that you haven’t set up your sender address yet. To fix this, go to app/config/mail.php and fill in the relevant details.

Of course to actually send the email you will need to set up an SMTP server. Personally I like SendGrid. In a future tutorial I will do a much deeper dive on setting up email related stuff in your Laravel application.

If you want to see the template for the default email, it is stored under app/views/auth/reminder.blade.php. You are of course free to change this, just ensure you leave the URL tag intact.

Creating the reset form

Next we will create the form that the user will land on after clicking the reset link in the email.

First create a new route:

Route::get('password/reset/{token}', array(
  'uses' => 'PasswordController@reset',
  'as' => 'password.reset'

This route requires that the secret token is set in the URL. This will be set automatically in the reminder email.

Next add the following method to your Password Controller file to request the correct View:

public function reset($token)
  return View::make('password.reset')->with('token', $token);

Notice how this method will accept the token from the URL and assign it the View.

And finally, create another View under app/views/password called reset.blade.php and copy the following code:

@if (Session::has('error'))
  {{ trans(Session::get('reason')) }}

{{ Form::open(array('route' => array('password.update', $token))) }}

  <p>{{ Form::label('email', 'Email') }}
  {{ Form::text('email') }}</p>

  <p>{{ Form::label('password', 'Password') }}
  {{ Form::text('password') }}</p>

  <p>{{ Form::label('password_confirmation', 'Password confirm') }}
  {{ Form::text('password_confirmation') }}</p>

  {{ Form::hidden('token', $token) }}

  <p>{{ Form::submit('Submit') }}</p>

{{ Form::close() }}

Again this is a relatively simple form. First we display any errors at the top. Then we create fields so the user can enter their email address and choose a new password.

Notice how I’ve also set the token as a hidden field and I’ve also set it as a parameter in the action route. The hidden token is used to validate against the database and the URL parameter is used as a requirement of the route.

Updating the password

And finally we can create the route and method to actually update the User’s password.

Firstly create the POST route:

Route::post('password/reset/{token}', array(
  'uses' => 'PasswordController@update',
  'as' => 'password.update'

Next create the method on the Password Controller:

public function update()
  $credentials = array('email' => Input::get('email'));

  return Password::reset($credentials, function($user, $password)
    $user->password = Hash::make($password);


    return Redirect::to('login')->with('flash', 'Your password has been reset');

Again this uses some Laravel trickery to do the heavy lifting. Laravel will attempt to reset the password. If it is successful, a User instance and the password are sent to the closure so you can run the update.

Next I’m simply redirecting to the login page with a flash message.

The reset method on the Password class will automatically deal with the heavily lifting of validating the request. It will check to ensure that a valid token has been sent and it will check the credentials and that the passwords match for you.

If there is an error with what the user entered, Laravel will automatically redirect back to the form and set an error message with a reason in the Session.


And there you have it, very simply password reminder and reset functionality almost straight out of the box from Laravel. One of the beautiful things about Laravel 4 is it automatically deals with common bits of functionality like this for you, so you don’t have to reinvent the wheel on every project.

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

To view a full listing of the tutorials in this series, click here.

Philip Brown

Hey, I'm Philip Brown, a designer and developer from Durham, England. I create websites and web based applications from the ground up. In 2011 I founded a company called Yellow Flag. If you want to find out more about me, you can follow me on Twitter or Google Plus.

  • Jerry James

    Thanks for the wonderful tutorials. Am understanding laravel better and better everyday. Please, where can i get pointed to connecting Laravel with angularjs? thanks alot

    • Thank you Jerry :)

      Do you mean a tutorial? I don’t remember ever seeing a Laravel + Angular tutorial. I’m sure someone will have written about it at some point.

      I think I’m going to be using Ember for Cribbb, so subscribe to the Culttt list if you want to follow along how I implement it in future tutorials :)

  • Bal

    Thanks Philip for this great tutorial, Alittle typo error in remind.blade.php, the route you are posting to is not password/request but password/reset.
    Am I right?

    • Good catch! Yes you are correct.

      Thank you, I’ll fix this now :)

  • ginro

    Thanks for the tutorial. Helps me a lot. Everything works I even get the password link in my email But i can’t figure this one out:

    Using this route:
    Route::post(‘password/reset’, array(
    ‘uses’ => ‘PasswordController@request’,
    ‘as’ => ‘password.request’

    I receive the mail but always got this error
    Stack trace:
    #0 C:wampwwwipq-infiltrationbootstrapcompiled.php(4791): IlluminateRoutingRouter->handleRoutingException(Object(SymfonyComponentRoutingExceptionMethodNotAllowedException))
    #1 C:wampwwwipq-infiltrationbootstrapcompiled.php(4779): IlluminateRoutingRouter->findRoute(Object(IlluminateHttpRequest))
    #2 C:wampwwwipq-infiltrationbootstrapcompiled.php(483): IlluminateRoutingRouter->dispatch(Object(IlluminateHttpRequest))
    #3 C:wampwwwipq-infiltrationbootstrapcompiled.php(472): IlluminateFoundationApplication->dispatch(Object(IlluminateHttpRequest))
    #4 C:wampwwwipq-infiltrationpublicindex.php(49): IlluminateFoundationApplication->run()
    #5 {main} [] []

    any idea ?

    • Have you set up the controller method correctly? Laravel is complaining about the method (MethodNotAllowedException). I would try just POSTing to that method to make sure you are able to hit it correctly.

    • Is this because the route is POST and after hitting Password::remind($credentials) it’s being routed back to the same route as a GET call and therefore failing (I’m having the same problem)?

      • Yeah you need to create routes for both POST and GET. If you haven’t created them, that will be a problem.

  • Jake

    Having the same issue as ginro…

    • If you have all of the routes and controllers set up correctly then it’s hard for me to diagnose without seeing your code.

      Does the view load at all?

      Are you pulling in stylesheets or javascript files that can’t be loaded from the relative URL?

      • jake

        I was trying to do it all from the routes.php but when I moved it to a controller it now works thanks.

  • gin93r

    Hi @philip_brown:disqus. I seem to be running into an issue where the password doesn’t get updated. The process flow works. I request a reset, I get the link, follow it and change the password. Successfully redirected to the login page and the new credentials are invalid. The old ones are still set. Have you run into this at all?

    • gin93r

      update: I think I’ve narrowed the password saving error to an “alpha_num” rule on the password. For some reason, the $user in the update function errors silently with a “the password can only contain letters and numbers” which it did. Removing that, the password saved. Unfortunately, something is still messed up somewhere as trying to login with that password results in an incorrect password….

      • Hmm, that’s strange, try without the Hash::make($password) to see if the password is getting updated correctly.

      • gin93r

        alright. I think I’ve figured out the password issue. In the Password controller’s update method the following line is causing the (my?) issue:

        $user->password = Hash::make($password);

        I’m using Magniloquent (not the tutorial version) which i believe auto-hashes passwords. So basically it was being hashed twice.

        • Ahhhhh of course! Doh, can’t believe I was fooled by my own package! Nice one for noticing :)

          • gin93r

            Haha! For sure. I can’t believe it took me so long to realize that’s what was happening. Sometimes we just stare at things too long I think. I still have to figure out why there was an error with the alpha_num setting but at least I can get the password to save and update now.

          • Haha, exactly! Hmm, do you have a validation rule on the model?

          • gin93r

            I do. I think it IS actually working except that it will fail silently; giving the illusion that it succeeded. Basically if the validation rules aren’t met, it will still route to the login page, but nothing will be entered into the database. According to the Laravel docs, the remind method should route it back to the page and show errors if they are present. This doesn’t seem to be the case. Something must be getting in the way of that.

          • Ah I see what you mean. All you need to do is to determine if $user->saved() returns false and redirect back to the form as you would with any other form submission. The code I have above doesn’t have that error response.

          • gin93r

            This actually brings up some other weird issues.

            Password::reset seems to ignore validation rules set by the model. At least I think it does. My validation requires 8 characters. If I type 4 characters I will get an error stating that the password requires 6 or more. Typing exactly six (or more) will produce what seems like a successful reset. But this isn’t the case. It’s failing silently.

            I tried if($user->save()) { … } return Redirect::refresh()->withErrors($user->errors());

            note: I’ve also tried if($user->isSaved())…

            What will happen is that it will refresh the page but without displaying any errors and the password will not be changed. What it will also do is remove the reset token / email from the database.

            I should mention that instead of forcing the user to enter in their email address a second time, I pull the email address from the password_reminders table from the token that is passed. I felt this was a better user experience. I did it like this:

            $email = DB::table(‘password_reminders’)->where(‘token’,$id)->pluck(’email’);
            $credentials = array(’email’=>$email);

            Again – I just find it odd that the reminder will be removed from the database on fail and that it will fail either silently or with incorrect errors.

          • Hmm that is weird. I’ll have to have a dig through the code to see what’s going on.

          • gin93r

            I don’t know enough about extending Laravel to know what to change/fix, but the culprit is the Illuminate/Auth/Reminders/PasswordBroker class.

            The “rules” for the password (if I’m reading correctly) are hard coded in the validNewPasswords method:

            return $password and strlen($password) >= 6 and $password == $confirm;

            At least that’s part of the problem.

          • Ah really?! That’s interesting. You should open a Pull Request on Laravel so you can override it if required. That seems weird that it is hard coded.

            Excellent work finding it :)

          • gin93r

            maybe “hard coded” wasn’t the correct phrase. It’s a protected method in the class. But it’s still weird that (if i understand correctly so far) it’s handled differently than other validation.

            I know that I’m using your package to validate in the model, but why wouldn’t the Password::reset follow the same method of validation that the register user does? Seems odd. Again it could be a misunderstanding on my part as I’m pretty green to Laravel.

            As far as a Pull Request – I’m probably more green with git than I am with Laravel. I’m not even sure what a pull request is. Though I’ll look it up once I finish typing…

  • misbah

    Why you don’t check $token first at reset function ? (check token with database)
    Thief can insert anything and change password if we don’t check the token is real or not, am I right ?

    • The token is validated against the database, or yeah it would be pretty pointless if you could reset anyone’s password.

  • dech

    Hello , how can I edit subject of email that send for reset password?

  • Paul

    Just a quick thing. Email template is located in app/views/emails/auth/reminder.blade.php

  • Pingback: How to structure your Sass for large web applications | Culttt()

  • Moazam

    Great work Philip. Excellent laravel tutorials! I would love to see a series on developing a large scale application by using laravel framework. I hope you will work on it. Keep it up!

  • gin93r

    Hi Philip,

    I’ve run into another “issue.” Right after posting the password reset request (Password::remind…) it sends the email, however, it flashes to the screen “reminders.sent” and I can’t seem to find a way to change this, or route to a different location. Ideally I’d like to route to my landing page with a flash message. Any thoughts?

    • Hmm, do you have your route set up correctly? What do you mean it flashes on the screen? Does the page die or does it redirect somewhere else?

      • gin93r

        All routes were set up properly. Basically it would reload the same page, only with “reminders.sent” on the page.

        I learned that the Reminder stuff was overhauled in 4.1 a bit and generated a new controller via artisan and that seemed to fix this issue. The methods aren’t the same as the ones for 4.0. Thanks for the response.

        • Ah cool. Yeah I haven’t had a look at this since the rewrite in 4.1. Glad you got it sorted though!

        • Sersun

          gin93r, would you mind sharing how you solved this?

          • gin93r

            Yes – basically, generate the proper controller. The documentation will walk you through it. This is of course for 4.1. The controller will include all of the methods that are expected.


          • gin93r

            Wow – I guess I wasn’t getting notified via email. I’m sorry. I know it’s way too late, but the solution was to generate the new Controller. As I mentioned above, the method names were changed in 4.1

  • How would one go about writing tests for this? Im just getting into the basics of unit testing and it would be good to see how the tests would be structured for this.

    • I wouldn’t unit test this code because it’s nearly all Laravel code that is doing the hard work. You could do integration tests, but even then I probably wouldn’t go nuts on testing it because you can be pretty confident that Taylor has already got the tests in place to ensure that it is working correctly.

      That is a good point though, as someone who is new to tests, how do you determine what to test and what not to test. I think I might write a post on that!

      Thanks Ben, hope that answered your question :)

      • Leaving this as an integration test would make sense, in my unit tests I was considering trying to mock the Password class but as it provides quite a bit of functionality I wasnt to sure where to start with it.

        Great site by the way, some more posts on testing and the repository pattern would be awesome :)

  • Jason Judge

    The template provided for the email body is HTML, and by default only this HTML body will be sent. We were finding this is ranked high on the SPAM scale by many of the bigger email providers (Hotmail, Yahoo), causing problems for our users.

    It seems that you can provide a text template too and send a multipart email. In config/auth.php, the reminder.email setting will be set to the HTML template, which is just a string – ’emails.auth.reminder’.

    Change that to an array – array(’emails.auth.reminder’, ’emails.auth.reminder-plain’) – the first element will be used as the view for the HTML part and the second element will be used as the view for the plain text part. This knocks a couple of points off our SPAM rating for these emails, and no so many of them are getting lost.

    • Thanks Jason! I hadn’t really looked into sending text only emails as well, I’m glad it’s easy to set up. How do you send your emails? You should look into using something like http:/sendgrid.com I’ve found them to be really good.

      • Jason Judge

        It wasn’t so much text-only, although that is possible (the HTML body can be overwritten with a text version in the callback). It was more about a multi-part text+html email, which are looked at more favourably wrt SPAM

        We use Sendgrid for bulk emailing, so know it works well. Our Sendgrid account has tracking turned on for newsletter tracking, which means that all emails have their URLs changed to tracking URLs. Unfortunately that cannot be turned off per-sender so we would need to set up a second account and that would be an extra cost. If a client is paying for that, cool, but it is not always possible. We might have to bite that bullet though for the pure simplicity of having someone else deal with all this stuff (SPF, DKIM etc.).

        • Ah I see!

          Yeah it’s a shame that you couldn’t use Sendgrid in more of a whitelabel way or split it into different accounts for different clients. Perhaps one day they will release something like that.

          Yeah, I’m all about paying someone else to deal with headaches and make my life simple :)

  • Pingback: Model Presenters in Laravel 4 | Culttt()

  • Chokkan Web


    I think that Form::text(‘password’) is a bad idea, you should have Form::password(‘password’)

  • Walder

    Hi, Phillip. How can I change the min lenght of the password? The default is 6, isn’t?

  • juni

    Hello, I would like to ask if where is the token, password, and password_confirmed being process,.. I think its processed in the Password::reset but I dont know if you ever used the three fields.

    • The password reset functionality was changed in 4.1 I think, so it’s perhaps moved?

  • Bob Brown

    Do you have any suggestions for how to populate the email address in the form when the user clicks the password reset link? My form is displayed but asks for email and two passwords. The details of who is being reset at that point it not passed through. It looks like this is a deliberate design decision from the Laravel component.

    • Hmm, I haven’t looked into it in great depth to be honest. I guess if it is a deliberate design decision you might have to write your own version or suggest it as a feature.

      • Bob Brown

        I worked out something. You have to include the email address in the reset link. The reset link then looks like this:


        To do this:

        Edit the emails/auth/reminder.blade.php and use:
        {{ URL::to(‘password/reset’, array($token,$user->email)) }}

        And then in RemindersController::getReset() do this:
        return View::make(‘password.reset’,compact(’email’))->with(‘token’, $token);

        Finally in views/password/reset.blade.php:

        Sweet as.

        • Ah nice! Excellent work Bob! I’ll definitely be using that technique :)

        • Mark Roberts

          What about the route?

          I tried changing:




          Didn’t work. Any suggestions? Thanks.

          • Which bit didn’t work? I would pass the email through as a query parameter.

  • Roberto Alonso

    Thank you so much!! I could implement my reset password system! I was trying to do this with Laravel documentation but I was not able to. This tutorial helped me a lot! Thank you!

  • wexdev

    Hi, great tutorial. Just wondering if you have any thoughts on how to implement from a RESTful point of view. We are trying to do this for our API. We want to provide an API call which will allow clients to provide the front end form to capture the password reset. So far we can send the email to the user to reset their password once the have sent a message to the API call with the email address in the POST field. But, is there a way to change the URI which is specfied in the reset email, so that instead of using a route in our App the user gets sent to the 3rd party client (along with the token), which get the new password and then sends it with the token to a update password API call?
    Any ideas!!

    • Thank you,

      Yeah, but you would need to have those details inside your API. So you would just construct the URL from the the client’s URL and route to their reset form.

      • wexdev

        yes, but I cannot figure out how to change the default URL on the email sent to the users – -in views/emails/auth/reminder.blade.php there is {{ URL::to(‘password/reset’, array($token)) which I somehow need to change to be the URL which is passed in to the API Post with reset password with the email address.. I think once I can do this, then the client just sends the new passwords and $token back to the update API call..

        • The domain part of the URL is generated from the setting in your config file. So you would just not use the URL::to() method to generate the URL.

      • wexdev

        Hi Philip, can you suggest how to do this? Because I cannot seem to see anyway to modify the URL in the password reset email. I want the client to post in the reset form URL in the password reset request so that I can put this in the email along with the token, the client then captures the new password and the token and posts back to our change password API. But.. I cannot see how to achieve this!

  • Rafael Rossi

    Thanks, so helpfull :)

  • Washeul Islam-Vicky

    hi all of your tutorials are just awsome .its allways help me out . I am using this tutotial for one of my project its working fine i just want to change it a little but all i want to redirect to custom page with custom message ,rather than showing reset.user or somthing like that how can i do that ..tnx in advanced

    • Thank you!

      You would just need to add the redirect to that part of the RemindersController.

      • Jonathan

        I’ve tried this with make view and it doesnt work, where should i edit it ?
        Thanks for everything

        • What are you trying to do?

          • Jonathan

            When the email is sent correctly it shows view only containing “reminders.sent” and when it fails it sais “reminders.user”, how do i change that so it makes a view like sending it home or a custom new one

            Thanks a lot

          • Is you code on GitHub? I’ll take a look

          • R.


            return Password::remind($attributes);


            switch (Password::remind($attributes)){

            case Password::INVALID_USER:
            return Redirect::back()->with(‘error’, Lang::get($reason));

            case Password::REMINDER_SENT:
            return Redirect::back()->with(‘status’, Lang::get($reason));


      • Washeul Islam-Vicky

        hi , in your tutorial you did not use RemindersController ,do i have to create that controller? i have tried to implement redirect code in the password controller but its not working could you please post sample code it will be really helpful .thank you

    • osjrod

      how you resolve that?

      • Washeul Islam-Vicky

        i am still trying but happening :(

  • Jonathan

    I’ve done everything as you’ve said but this error keeps comming after you enter the new password
    ErrorException (E_UNKNOWN)
    Undefined index: password

    in this function

    protected function validNewPasswords(array $credentials)
    list($password, $confirm) = array($credentials[‘password’], $credentials[‘password_confirmation’]);
    if (isset($this->passwordValidator))

    Do you have any clues on why this could be happening?

    Thanks in advance

    • The password key is not in your $credentials array.

      • Jordan

        It isn’t in yours…


        $credentials = array(’email’ => Input::get(’email’));


        $credentials = array(’email’ => Input::get(’email’), ‘password’ => Input::get(‘password’), ‘password_confirmation’ => Input::get(‘password_confirmation’));

        • Hmm, yeah I think Laravel’s password reminder functionality has changed since I wrote this tutorial.

    • osjrod

      how do you resolve that problem?

  • ahmed

    hi nice tutorial :) but when i enter the new password im getting this error

    Undefined index: password

    • Have another look at setting the credentials variable. I’ve updated this post.

  • osoandrade

    Great tutorial! Thank you so much!

    A quick update: Instead of:

    php artisan auth:reminders

    you now have to issue:

    php artisan auth:reminders-table

    Also, I was still having problems with the “Undefined index: password” error. On the PasswordController change the “update()” function from:

    $credentials = array(’email’ => Input::get(’email’));


    $credentials = array(’email’ => Input::get(’email’), ‘password’ => Input::get(‘password’), ‘password_confirmation’ => Input::get(‘password_confirmation’), ‘token’ => Input::get(‘token’));

    That should do it!

  • Don Marco

    Sorry, new to laravel. if my email column was in a different name such as emailaddress, how should i change the controllers and views for the password reset?