Custom Forgot & Reset Password Functionality in Laravel

Using the custom forgot password in laravel tutorial you will learn how to implement custom forgot and reset password functionality in laravel 10. By default laravel provides us authentication where we can easily authenticate user login, register, forgot password and reset it.

In the previous article we already added custom authentication in laravel in an easy way. If you want only forgot and reset password in laravel let’s go the step by step guide:

Laravel Forgot & Reset Password Tutorial

In this example, we have a forgot password form to get the username or email to recover the password. After form submits, we are sending password recovery email to the user. The Password recovery email has a link to the page where we can reset the password.

Step 1: Create Blade Files

First, create new folder layouts in your resources>views directory, then create a new file dashboard.blade.php in the layouts folder same as below.

resources/views/layouts/dashboard.blade.php

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>Laravel Ajax CRUD Example Tutorial with - CodingDriver</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.datatables.net/r/bs-3.3.5/jq-2.1.4,dt-1.10.8/datatables.min.css"/>

  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
  <script src="https://cdn.datatables.net/r/bs-3.3.5/jqc-1.11.3,dt-1.10.8/datatables.min.js"></script>
</head>
  <style>
  .alert-message {
    color: red;
  }
</style>
<body>

<div class="container">
    <h2 style="margin-top: 12px;" class="alert alert-success">Laravel Ajax CRUD Application -
       <a href="https://www.codingdriver.com" target="_blank" >CodingDriver</a>
     </h2><br>
     <div class="row" style="clear: both;margin-top: 18px;">
       <div class="col-12 text-right">
          <a href="/login" class="navbar-brand">
          Laravel Custom Auth
          </a> <button type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" class="navbar-toggler"><span class="navbar-toggler-icon"></span></button>
          <div id="navbarSupportedContent" class="collapse navbar-collapse">
             <ul class="navbar-nav mr-auto"></ul>
             <ul class="navbar-nav ml-auto">
                <li class="nav-item"><a href="/login" class="nav-link">Login</a></li>
                <li class="nav-item"><a href="/register" class="nav-link">Register</a></li>
             </ul>
          </div>
       </div>
    </div>
    <div class="row">
        <div class="wrapper ">
           <div class="main-panel">
             @yield('content')
           </div>
         </div>
    </div>
</div>
</body>
</html>

Now create a email blade file in your views>customauth>password directory and add below code.

resources/views/customauth/passwords/email.blade.php

@extends('layouts.dashboard')
@section('content')

<div class="container">
     <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
              <div class="card-header">Reset Password</div>
                
               <div class="card-body">
                    @if (session('status'))
                         <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif
                  
                   <form method="POST" action="/forget-password">
                        @csrf
                          <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">E-Mail Address</label>
                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" autocomplete="email" autofocus>

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                   <div class="form-group row mb-0">
                         <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    Send Password Reset Link
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

@endsection

Step 2: Add Routes

Now update your route in web.php file.

Routes/web.php

Route::get('/forget-password', 'ForgotPasswordController@getEmail');
Route::post('/forget-password', 'ForgotPasswordController@postEmail');

Step 3: Create Forget Password Migration

If you add your gmail in your forget password input then your send a link via mail function using controller function so here you need to add a Forget password migration to running just below command.

php artisan make:migration create_password_resets_table

After creating password reset table add below code on it.

<?php 

use Illuminate\Support\Facades\Schema; 
use Illuminate\Database\Schema\Blueprint; 
use Illuminate\Database\Migrations\Migration; 

class CreatePasswordResetsTable extends Migration { 

    /**
     * Run the migrations.
     *
     * @return void
     */
    
   public function up()
    {
        Schema::create('password_resets', function (Blueprint $table) {
            $table->string('email')->index();            
            $table->string('token');
            $table->timestamp('created_at')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('password_resets');
    }
}

Now inserting it on database run below command.

php artisan migrate

Step 4: Create Forget Password Controller

Now you need to create a ForgotPasswordController just run below command.

php artisan make:controller ForgotPasswordController

Now update below code in your forgot password controller.

app/Http/Controllers/ForgotPasswordController.php

<?php 

namespace App\Http\Controllers; 

use Illuminate\Http\Request; 
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Carbon\Carbon; 

class ForgotPasswordController extends Controller
{
  public function getEmail()
  {

     return view('customauth.passwords.email');
  }

 public function postEmail(Request $request)
  {
    $request->validate([
        'email' => 'required|email|exists:users',
    ]);

    $token = str_random(64);

      DB::table('password_resets')->insert(
          ['email' => $request->email, 'token' => $token, 'created_at' => Carbon::now()]
      );

      Mail::send('customauth.verify', ['token' => $token], function($message) use($request){
          $message->to($request->email);
          $message->subject('Reset Password Notification');
      });

      return back()->with('message', 'We have e-mailed your password reset link!');
  }
}

Now if you add an email to forget password option and send then its go in your mailtrap where you can click the link and update your password easily.First add your mailtrap details in your .env file. If you have not any mailtrap account then please create first to go mailtrap.io. Mailtrap is a free mail testing website.

Step 5: Add Mailtrap Details in .env File

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=331e7bae#####
MAIL_PASSWORD=25a1052b#####
MAIL_ENCRYPTION=null

Now Checkout mail trap where your received an email. Below create a blade file to sending email in your views>customauth directory this file go in your mailtrap inbox.

Step 6: Create Verify Blade

resources/views/customauth/verify.blade.php

@extends('layouts.dashboard')
@section('content')

<div class="container">
     <div class="row justify-content-center">
         <div class="col-md-8">
             <div class="card">
                 <div class="card-header">Verify Your Email Address</div>
                   <div class="card-body">
                    @if (session('resent'))
                         <div class="alert alert-success" role="alert">
                            {{ __('A fresh verification link has been sent to your email address.') }}
                        </div>
                    @endif
                    <a href="http://customlaravelauth.co/{{$token}}/reset-password">Click Here</a>.
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Now click the link which is received in your inbox now you redirect a link where your update your new password checkout how its work.

Step 7: Create Reset Password Routes

Route::get('/reset-password/{token}', 'ResetPasswordController@getPassword');
Route::post('/reset-password', 'ResetPasswordController@updatePassword');

Step 8: Create Reset Password Controller

After create reset password routes now you need to create a new controller ResetPasswordController in your App>Http directory.

php artisan make:controller ResetPasswordController

Now add below code in this controller.

app/Http/Controllers/ResetPasswordController.php

<?php 

namespace App\Http\Controllers; 
use Illuminate\Http\Request; 
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use App\User; 

class ResetPasswordController extends Controller { 

  public function getPassword($token) { 

     return view('customauth.passwords.reset', ['token' => $token]);
  }

  public function updatePassword(Request $request)
  {

  $request->validate([
      'email' => 'required|email|exists:users',
      'password' => 'required|string|min:6|confirmed',
      'password_confirmation' => 'required',

  ]);

  $updatePassword = DB::table('password_resets')
                      ->where(['email' => $request->email, 'token' => $request->token])
                      ->first();

  if(!$updatePassword)
      return back()->withInput()->with('error', 'Invalid token!');

    $user = User::where('email', $request->email)
                ->update(['password' => Hash::make($request->password)]);

    DB::table('password_resets')->where(['email'=> $request->email])->delete();

    return redirect('/login')->with('message', 'Your password has been changed!');

  }
}

Step 9: Create Reset Password Blade File

Now create to showing reset password option blade file in your views>customauth directory.

resources/views/customauth/passwords/reset.blade.php

@extends('layouts.dashboard')
@section('content')

<div class="container">
     <div class="row justify-content-center">
         <div class="col-md-8">
            <div class="card">
                 <div class="card-header">Reset Password</div>
                      <div class="card-body">
                          <form method="POST" action="/reset-password">
                           @csrf
                           <input type="hidden" name="token" value="{{ $token }}">
                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">E-Mail Address</label>
                          <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" autocomplete="email" autofocus>

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>
    
                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">Password</label>
                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" autocomplete="new-password">

                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>

                        </div>

                      <div class="form-group row">
                            <label for="password-confirm" class="col-md-4 col-form-label text-md-right">Confirm Password</label>
                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" autocomplete="new-password">
                            </div>
                        </div>

                     <div class="form-group row mb-0">
                           <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    Reset Password
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

@endsection

Now the laravel custom forgot & reset password tutorial example is completed. If you have any question please add your query in comment section. I hope this help for you.

7 thoughts on “Custom Forgot & Reset Password Functionality in Laravel”

Leave a Comment