Skip to content

Authentication Documentation.

Amirul Islam Anirban edited this page Oct 27, 2023 · 11 revisions

Service Providers and Container

app/Providers: You can Register any application services and bootstrap any application service and want to do something before handling the request.

Make providers

composer providers

The command line interface will ask you for a provider name, you enter a name. It will automatically add "ServiceProvider" to the name you provided. For example you want to create a provider named "example". Then your provider class will be ExampleServiceProvider.php

After creating the provider add it to the provider array in the 'config/app.php' file.

'providers' => [
    App\Providers\ExampleServiceProvider::class,
],
namespace App\Providers;

use Devamirul\PhpMicro\core\Foundation\Application\Container\BaseContainer;
use Devamirul\PhpMicro\core\Foundation\Application\Container\Interface\ContainerInterface;

class ExampleServiceProvider extends BaseContainer implements ContainerInterface {

    /**
     * Register any application services.
     */
    public function register(): void {
        //
    }

    /**
     * Bootstrap any application services
     * and if you want to do something before handling the request.
     */
    public function boot(): void {
        //
    }

}

Bind container:

public function register(): void {

    $this->app->bind('example', function () {
        return new example();
    });

}

Resolve container:

app()->make('example');

Get all bound container:

app()->getBindings();

Configuration:

Open config folder, Here you will find some predefined files which you can modify as you wish.

The predefined config files are :- app.php auth.php auth.php database.php mail.php middleware.php

config:

As you can change as per your wish in "app.php".

return [
    /**
     * Application Name.
     */
    'app_name'  => env('APP_NAME', 'PhpMicroFramework'),

    /**
     * Application Url.
     */
    'app_url'   => env('APP_URL', 'http://localhost:8000'),

    /**
     * Application Home path.
     */
    'home_url'  => '/',

    /**
     * Application Timezone.
     */
    'timezone' => 'Asia/Dhaka',

    /**
     * Autoloaded All Service Providers.
     */
    'providers' => [
        AppServiceProvider::class,
        ApplicationContainer::class
    ],
];

Request and Response:

Request:

framework's Devamirul\PhpMicro\core\Foundation\Application\Request class provides an object-oriented way to interact with the current HTTP request being handled by your application as well as retrieve the input that were submitted with the request.

Accessing The Request:

You have 2 ways to access the session.

  1. You can get requests through the facade.
use Devamirul\PhpMicro\core\Foundation\Application\Facade\Facades\Request;

Request::input();
  1. You can get requests through the request helper function.
request()->all();

You get the following methods from the Request class.

request()->input();

request()->input('name', 'default');

request()->only('name', 'email');

request()->path();

request()->query();

request()->query('name');

request()->method();

request()->all();

Also you will get methods.

isGet() isPost() isPut() isPatch() isDelete()

Response:

All routes and controllers should return a response to be sent back to the user's browser. The most basic response is returning a string from a route or controller.

Accessing The Response:

You can get some response helper function, you can do method chaining.

redirect('/link');

redirect('/link')->withData();

back();

back()->withError();

Routes:

routes/web.php: It is a simple and fast and lightweight route, inspired by Laravel route. You can do almost everything in this route as in Laravel route.

You can give each route a unique name.

Router::get('/', [WelcomeController::class, 'index'])->name('welcome');

or

Router::get('/welcome', function(){
    return view('welcome');
})->name('user');

You can use dynamic route, you just need to use the ":" sign. This type of Route Patterns contain dynamic parts which can vary per request. Where you can get the dynamic value in the route function if you want.

You can do method chaining if needed.

Router::get('/users/:id', function(int $id){
    return 'User id - ' . $id;
})->where('^\d+$')->name('user');

You can make the dynamic parameter optional if needed.

Router::get('/users/:id?', function(?int $id = null){
    return 'User id - ' . $id;
})->where('^\d+$')->name('user');

Using the Route::fallback method, you may define a route that will be executed when no other route matches the incoming request.

Route::fallback(function () {
    //
});

See the documentation for my "p-router" package for details:- p-router

Middlewares:

Middleware provide a convenient mechanism for inspecting and filtering HTTP requests entering your application.

The predefined middleware files are :- AuthMiddleware.php GuestMiddleware.php CsrfMiddleware.php

By default you will get request instance in handle method.

Make middleware

composer middleware

The command line interface will ask you for a middleware name, you enter a name. It will automatically add "Middleware" to the name you provided. For example you want to create a middleware named "example". Then your middleware class will be ExampleMiddleware.php

namespace App\Http\Middleware;

use Devamirul\PhpMicro\core\Foundation\Application\Request\Request;
use Devamirul\PhpMicro\core\Foundation\Middleware\Interface\Middleware;

class AuthMiddleware implements Middleware {
    /**
     * Handle an incoming request.
     */
    public function handle(Request $request, array $guards) {
        //
    }
}

For example, This framework includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to your application's login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

use Devamirul\PhpMicro\core\Foundation\Application\Facade\Facades\Auth;
use Devamirul\PhpMicro\core\Foundation\Application\Request\Request;

public function handle(Request $request, array $guards) {
    if (!empty($guards)) {
        foreach ($guards as $guard) {
            if (!Auth::guard($guard)->check() && $guard === 'admin') {
                return redirect('/admin/login');
            }
        }
    } elseif (!Auth::check()) {
        return redirect('/login');
    }
    return;
}

Add middleware

// TODO: add config We can easily add middleware to root. As Laravel does.

Router::get('/users/:id', function(int $id){
    return 'User id - ' . $id;
})->name('users')->middleware('auth');

We can optionally pass the guard name as a parameter to the middleware if there is multiple auth using guard.

Router::get('/login', [AuthenticatedController::class, 'create'])->name('login')->middleware('guest:admin');

Controllers:

app/Http/Controllers: Controllers respond to user actions (submitting forms, show users, any action etc.). Controllers are classes that extend the BaseController class.

Controllers are stored in the app/Controllers folder. A sample Welcome controllers are included. Controller classes need to be in the App/Controllers namespace. You can add subdirectories to organize your controllers.

By default you will get request instance in each method.

Make controller

composer controller

The command line interface will ask you for a controller name, you enter a name. It will automatically add "Controller" to the name you provided. For example you want to create a controller named "example". Then your controller class will be ExampleController.php

namespace App\Http\Controllers;

use Devamirul\PhpMicro\core\Foundation\Application\Request\Request;
use Devamirul\PhpMicro\core\Foundation\Controller\BaseController;

class UserController extends BaseController {
    /**
     * User show method.
     */
    public function show(Request $request) {
        return 'user name -' . $request->input('name');
    }
}

Views:

Views are used to display information. Views separate your controller / application logic from your presentation logic and are stored in the resources/views directory. No database access or anything like that should occur in a view file.

Fortunately you get a helper function of the main 'view' class.

Router::get('/welcome', function(){
    return view('welcome');
})->name('welcome');

If you want to pass data to "view" files, you may pass an array of data to views to make that data available to the view:

return view('welcome', ['name' => 'Amirul']);

When passing information in this manner, the data should be an array with key / value pairs. After providing data to a view, you can then access each value within your view using the data's keys, such as

<?php echo $name; ?>

You can send a status code if you want.

return status(200)->view('welcome');

You can set a different layout for the "view" file if you want. By default the layout will be "app.view.php".

return layout('main')->view('welcome');

or

return layout('main')->status(200)->view('welcome');

Models:

// TODO: cli Models are used to get and store data in your application. They know nothing about how this data will be presented in the views. Models extend the src\core\Foundation\Model class and use PDO to access the database (by Medoo). They're stored in the app/Models folder.

namespace App\Models;

use Devamirul\PhpMicro\core\Foundation\Models\BaseModel;

class Users extends BaseModel {
    protected $table = 'editors'
}

If your model's corresponding database table does not fit this convention, you may manually specify the model's table name by defining a table property on the model:

protected $table = 'editors'

Database:

Almost every modern web application interacts with a database. micro framework makes interacting with databases extremely simple across a variety of supported databases using SQL.

Medoo is handling all queries with SQL-92 standard. You should keep in mind the quotation marks in the query, or use prepared statements to prevent SQL injection as possible.

Internally it uses a PHP database package called Medoo.

The configuration for database services is located in your application's config/database.php configuration file. In this file, you may define all of your database connections, as well as specify which connection should be used by default.

Config:

return [
    /**
     * Default Database Connection Name.
     */
    'default'     => env('DB_CONNECTION', 'mysql'),

    /**
     * Define multiple database Configurations.
     */
    'connections' => [
        'mysql' => [
            'driver'   => 'mysql',
            'host'     => env('DB_HOST', '127.0.0.1'),
            'port'     => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'php_micro_framework'),
            'username' => env('DB_USERNAME', 'root'),
            'password' => env('DB_PASSWORD', ''),
            'error'    => env('DB_ERROR', 'PDO::ERRMODE_EXCEPTION'),
        ],
    ],
];

DB instance:

DB::db() actually returns a Medoo singleton instance behind the scenes.

DB::db();

You can easily perform tasks using model.

Model:

If your model's corresponding database table does not fit this convention, you may manually specify the model's table name by defining a table property on the model:

protected $table = 'editors'

The target columns of data will be fetched and The WHERE clause to filter records. select($columns, $where(optional))

$user = new User();

$user->select([
	"user_name",
	"email"
], [
    // Where condition.
	"user_id[>]" => 100
])->getData();

Table Joining:

SQL JOIN clause can combine rows between two tables. Medoo provides a simple syntax for the JOIN clause.

[>] ==> LEFT JOIN [<] ==> RIGHT JOIN [<>] ==> FULL JOIN [><] ==> INNER JOIN

$user = new User();

$user->select([
	// Here is the table relativity argument that tells the relativity between the table you want to join.
	"[>]account" => ["author_id" => "user_id"]
], [
	"post.title",
	"account.city"
])->getData();

Data Mapping:

$user = new User();

$user->select([
	"[>]account" => ["user_id"]
], [
	"post.content",

	"userData" => [
		"account.user_id",
		"account.email",

		"meta" => [
			"account.location",
			"account.gender"
		]
	]
], [
	"LIMIT" => [0, 2]
])->getJson()->getData();

Insert:

Insert one or more records into the table. insert($values)

$user = new User();

$user->insert([
	[
		"user_name" => "foo",
		"email" => "[email protected]",
	],
	[
		"user_name" => "bar",
		"email" => "[email protected]",
	]
]);
// Get last inserted id.
$user->id();

Errors And Error Handling:

$user = new User();

$user->select([
	"user_name",
	"email"
])->getData();

// DB::db()->error and DB::db()->errorInfo will be null value if no error occurred.
// You can simply check if the value is null or not to know about that.
if ($user->error()) {
	echo "Error happened!";
};

See the Medoo documentation for details.

You can invoke all methods of Medoo from the model.

However, 2 things should be noted.

  1. You cannot use the table names shown in the "sql query " in the Medoo documentation, because the framework will magically choose the table names based on the model. So model name and table name should be same.

In meddo documention

// Here the table name "user" is used.
DB::db()->select("users", [
	"user_name",
	"email"
]);

In framework

// Here automatically the table name will be obtained from the "new User()" model.
$user = new User();

$user->select([
	"user_name",
	"email"
]);
  1. Also you need to use "getData()" method to get the data.

In meddo documention

$user = DB::db()->select("users", [
	"user_name",
	"email"
]);

print_r($user);

In framework

$user = new User();

$user = $user->select([
	"user_name",
	"email"
])->getData();

print_r($user);

Also run customized raw queries easily.

Raw Query:

query($query)

DB::db()->query("SELECT email FROM account")->fetchAll();

The query() also supports prepared statements. Medoo will auto-detect the data type for input parameters.

DB::db()->query(
	"SELECT * FROM <account> WHERE <user_name> = :user_name AND <age> = :age", [
		":user_name" => "John Smite",
		":age" => 20
	]
)->fetchAll();

Medoo is based on the PDO object. You can access the PDO object directly via using $database->pdo, so that you can use all PDO methods if you needed, like prepare, transaction, rollBack, or more.

Transaction:

DB::db()->pdo->beginTransaction();

DB::db()->insert("account", [
	"user_name" => "foo",
	"email" => "[email protected]",
	"age" => 25
]);

/* Commit the changes */
DB::db()->pdo->commit();

/* Recognize mistakes and roll back changes */
DB::db()->pdo->rollBack();

Create a table:

create($table, $columns, $options)

DB::db()->create("account", [
	"id" => [
		"INT",
		"NOT NULL",
		"AUTO_INCREMENT",
		"PRIMARY KEY"
	],
	"first_name" => [
		"VARCHAR(30)",
		"NOT NULL"
	]
]);

Guards:

config/auth.php: The framework offers you a "guard" system for multiple authentication. You can use multiple guards there if you want.

return [
    /**
     * Set Default authentication guards.
     */
    'defaults' => 'web',

    /**
     * Define multiple guards.
     */
    'guards'   => [
        'web'    => [
            'provider' => 'users',
            'model' => App\Models\Users::class,
        ],

        'editor' => [
            'provider' => 'editors',
            'model' => App\Models\Editors::class,
        ],
    ],
];

Authentication:

Many web applications provide a way for their users to authenticate with the application and "login". Implementing this feature in web applications can be a complex and potentially risky endeavor. For this reason, Micro framework strives to give you the tools you need to implement authentication quickly, securely, and easily.

Authentication Documentation

Mail:

Almost every modern web application provides mailing system . The framework helps you send mails very easily. It is very simple, below we will see its example.

Framework's email services may be configured via your application's 'config/mail.php' configuration file.

return [
    /**
     * Mailer Configurations.
     */
    'smtp'    => [
        'host'         => env('MAIL_HOST', 'sandbox.smtp.mailtrap.io'),
        'port'         => env('MAIL_PORT', 587),
        'username'     => env('MAIL_USERNAME', ''),
        'password'     => env('MAIL_PASSWORD', ''),
    ],

    /**
     * Global "From" Address.
     */
    'from' => [
        'address' => env('MAIL_FROM_ADDRESS', '[email protected]'),
        'name' => env('MAIL_FROM_NAME', 'PhpMicroFramework'),
    ],
];

Get mailer instance:

use Devamirul\PhpMicro\core\Foundation\Application\Mail\Mail;

Mail::mailer();

Send mail example:

// Default address from config file.
$mailConfig = config('mail', 'from');

// Send mail.
Mail::mailer()
        ->setFrom($mailConfig['name'], $mailConfig['address'])
        ->addTo('User', '[email protected]')
        ->setSubject('Welcome')
        ->setBody('Dear <strong>User</strong>, Thank you for registering')
        ->send();

Event:

Almost every modern web application provides event listener system. Micro framework's events provide a simple observer pattern implementation, allowing you to listen for various events that occur within your application And you can trigger events when needed.

Accessing The Request:

You can get events through the event helper function.

event();

Example:

public function boot(): void {

    event()->listen('welcome', function(){
        return 'welcome message';
    });

}

Router::get('/welcome', function(){
    return event()->trigger('welcome');
});

Sessions:

Since HTTP driven applications are stateless, sessions provide a way to store information about the user across multiple requests that can be accessed from subsequent requests.

The session can basically be divided into 2 parts.

  1. Session

  2. FlushSession

Session:

Accessing The Session:

You can store any type of data here. You have 2 ways to access the session.

  1. You can get session through the facade.
use Devamirul\PhpMicro\core\Foundation\Application\Facade\Facades\Session;

Session::set('example', 'example session string');
  1. You can get session through the session helper function.
session()->get('example');

Example:

// Return bool.
session()->has('example');
Session::has('example');

// Destroy session data by key.
session()->delete('example');
Session::delete('example');

FlushSession:

Sometimes you may wish to store items in the session for the next request. You may do so using the flushMessage() method. Data stored in the session using this method will be available immediately and during the subsequent HTTP request. After the subsequent HTTP request, the flashed data will be deleted. Flash data is primarily useful for short-lived status messages:

Accessing The FlushSession:

You can store any type of data here. You have 2 ways to access the FlushSession.

  1. You can get FlushSession through the facade.
use Devamirul\PhpMicro\core\Foundation\Application\Facade\Facades\Flush;

Flush::set('example', 'example session string');
  1. You can get FlushSession through the FlushSession helper function.
flushMessage()->get('example');

Example:

// Return bool.
flushMessage()->has('example');
Flush::has('example');

// Destroy session data by key.
Flush::delete('example');

Helpers:

Micro frameworks provide some helper methods for the convenience of developers.

Helpers Documentation

Manually Authenticating Users:

Micro framework's authentication facilities are made up of "guards". Guards define how users are authenticated for each request. For example, framework ships with a session guard which maintains state using session storage.

Your application's authentication configuration file is located at config/auth.php:

return [
    /**
     * Set Default authentication guards.
     */
    'defaults' => 'web',

    /**
     * Define multiple guards.
     */
    'guards'   => [
        'web'    => [
            'provider' => 'users',
            'model' => App\Models\Users::class,
        ],

         // Custom guard.
        'editor' => [
            'provider' => 'editors',
            'model' => App\Models\Editors::class,
        ],
    ],
];

Retrieving The Authenticated User:

You will often need to interact with the currently authenticated user. While handling an incoming request, you may access the authenticated user via the Auth facade's user method:

Auth::user();

or

auth()->user();

If needed, you may specify an authentication guard before calling the login method:

auth()->guard('editor')->user();

Determining If The Current User Is Authenticated:

To determine if the user making the incoming HTTP request is authenticated, you may use the check method on the Auth facade. This method will return true if the user is authenticated:

if (Auth::check()) {
    // The user is logged in...
}

Manually Authenticating Users:

The framework gives you a method called "attempt". With the help of which you can login very easily. The attempt method is normally used to handle authentication attempts from your application's "login" form.

(new AuthAttempt())->attempt(['email' => $email, 'password' => $password]);

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 'login' request form:

Router::get('/login', [AuthenticatedController::class, 'create'])->name('login')->middleware('guest');

Of course, we need to define a route to actually submit the login form. This route will be responsible for validating incoming requests and logging in the user:

Router::post('/login', [AuthenticatedController::class, 'store'])->name('login')->middleware('guest');
/**
 * Handle an authentication attempt.
 */
public function store(Request $request) {
    $validator = new Validator();

    $validation = $validator->validate($request->only('email', 'password'), [
        'email'    => 'required|email',
        'password' => 'required|min:6',
    ]);

    if ($validation->fails()) {
        $errors = $validation->errors();

        return back()->withError($errors);
    } else {
        $validatedData = $validation->getValidatedData();

        (new AuthAttempt())->attempt($validatedData);
    }
}

The attempt method accepts an array of key / value pairs as its first argument. The values in the array will be used to find the user in your database table. So, in the example above, the user will be retrieved by the value of the email column. If the user is found, the hashed password stored in the database will be compared with the password value passed to the method via the array. You should not hash the incoming request's password value, since the framework will automatically hash the value before comparing it to the hashed password in the database. An authenticated session will be started for the user if the two hashed passwords match.

Remember, Micro framework's authentication services will retrieve users from your database based on your authentication guard's configuration. The default config/auth.php configuration file instructs the app to use the app\Models\Users model when retrieving users. You may change these values within your configuration file based on the needs of your application.

If authentication is successful it will redirect to '/' route. Otherwise, redirect back with error data. By default '/' route will be given. You can change the redirect link if you want.

(new AuthAttempt())->attempt($validatedData, '/dashboard');

If needed, you may specify an authentication guard before calling the login method.

(new AuthAttempt())->guard('editor')->attempt($validatedData, '/editors/dashboard');

Get & Show validation errors:

<?= errors('email')?>

With example:

<form>
   <div class="mb-3">
       <label for="exampleInputEmail" class="form-label">Email address</label>
       <input type="email" name="email" class="form-control" id="exampleInputEmail" aria-describedby="emailHelp">

       <div id="emailHelp" class="form-text"> <?= errors('email')?> </div>
   </div>
</form>

Get & Show database errors:

<form>
   <?php if (hasError()): ?>
       <div class="alert alert-success mt-3" role="alert">
           <?= error() ?>
       </div>
   <?php endif?>
</form>

To manually log users out of your application, you may use the destroy method provided by the Auth facade. This will remove the authentication information from the user's session so that subsequent requests are not authenticated.

If logout is successful it will redirect to '/login' route. Otherwise. By default '/login' route will be given. You can change the redirect link if you want.

public function destroy() {
    (new AuthAttempt())->destroy();
}

For multiple guards:

public function destroy() {
    (new AuthAttempt())->guard('editor')->destroy('/editors/login');
}

Manually Registration Users:

The framework gives you a method called "register". With the help of which you can register very easily. The register method is normally used to handle registration from your application's "register" form.

public function store(Request $request) {
    $validator = new Validator();

    $validation = $validator->validate($request->only('name', 'email', 'password', 'confirm_password'), [
        'name'             => 'required',
        'email'            => 'required|email',
        'password'         => 'required|min:6',
        'confirm_password' => 'required|same:password',
    ]);

    if ($validation->fails()) {
        $errors = $validation->errors();

        return back()->withError($errors);
    } else {
        $validatedData = $validation->getValidatedData();

        (new AuthRegister())->register($validatedData);
    }
}

The register method accepts an array of key / value pairs as its first argument. A user will be created from the data in that array.

If registration is successful it will redirect to '/login' route. Otherwise, a "DatabaseErrorException" is returned. By default '/login' route will be given. You can change the redirect link if you want.

(new AuthRegister())->register($validatedData, '/editors/login');

If needed, you may specify an authentication guard before calling the login method:

(new AuthRegister())->guard('editor')->register($validatedData, '/editors/login');

If registration successfull redirect login form and show success message:

<form>
    <?php if (hasSuccess()): ?>
        <div class="alert alert-success mt-3" role="alert">
            <?=success()?>
        </div>
    <?php endif?>
</form>

Manually Forget Password Users:

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, Micro framework provides convenient services for sending password reset links and secure resetting passwords.

The sendLink method is normally used to handle send link from your application's "forget" form.

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:

Route::get('/forgot-password', function () {
    return view('forgot-password');
})->middleware('guest')->name('forgot.password');

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.

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:

public function store(Request $request) {
    $validator = new Validator();

    $validation = $validator->validate($request->only('email'), [
        'email' => 'required|email',
    ]);

    if ($validation->fails()) {
        $errors = $validation->errors();

        return back()->withError($errors);
    } else {
        $validatedData = $validation->getValidatedData();

        $email = $validatedData['email'];

        (new AuthReset())->sendLink($email);
    }
}

The sendLink method accepts email value as its first argument.

If the reset link is sent successfully, a mail will be sent to your mail address with the reset link. Otherwise, a "DatabaseErrorException" is returned. By default the root will be '/reset' path. You can change the path if you want.

(new AuthReset())->sendLink($email);

If needed, you may specify an authentication guard before calling the login method:

(new AuthReset())->guard('editor')->sendLink($email);

Your reset link will be:- "http://localhost:8000/reset?reset=ed9cdbc206c4e440f70cea5740932400c2c1a1a3e53ce7168460fb60868d2bc6316a0e403c63a0d7&[email protected]"

If you change the reset path:

(new AuthReset())->sendLink($email, 'your-reset-path');

Then the link will be like:- "http://localhost:8000/your-reset-path?reset=ed9cdbc206c4e440f70cea5740932400c2c1a1a3e53ce7168460fb60868d2bc6316a0e403c63a0d7&[email protected]"

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:

public function store(Request $request) {
    $validator = new Validator();

    $validation = $validator->validate($request->only('reset_token', 'email', 'password', 'confirm_password'), [
        'reset_token'      => 'required',
        'email'            => 'required|email',
        'password'         => 'required|min:6',
        'confirm_password' => 'required|same:password',
    ]);

    if ($validation->fails()) {
        $errors = $validation->errors();
        return back()->withError($errors);
    } else {
        $validatedData = $validation->getValidatedData();
        (new AuthReset())->resetPassword($validatedData);
    }
}

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. This route will receive a token param that we will use later to verify the password reset request:

Router::get('/reset', [NewPasswordController::class, 'create'])->name('reset')->middleware('guest');

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:

Router::put('/reset', [NewPasswordController::class, 'store'])->name('reset')->middleware('guest');
public function store(Request $request) {
    $validator = new Validator();

    $validation = $validator->validate($request->only('reset_token', 'email', 'password', 'confirm_password'), [
        'reset_token'      => 'required',
        'email'            => 'required|email',
        'password'         => 'required|min:6',
        'confirm_password' => 'required|same:password',
    ]);

    if ($validation->fails()) {
        $errors = $validation->errors();
        return back()->withError($errors);
    } else {
        $validatedData = $validation->getValidatedData();
        (new AuthReset())->resetPassword($validatedData);
    }
}

The resetPassword method accepts an array of key/value pairs as its first argument. That array will be validated by data token and email to see if you are valid for this request, if the email and token is valid your new password will be set.

If reset password is successful it will redirect to '/login' route. Otherwise, a "DatabaseErrorException" is returned. By default '/login' route will be given. You can change the redirect link if you want.

(new AuthReset())->resetPassword($validatedData, '/editors/login');

If needed, you may specify an authentication guard before calling the login method:

(new AuthReset())->guard('editor')->resetPassword($validatedData, '/editors/login');

After resetting the password, the token will be automatically deleted from the database.