How to create a custom user provider in Laravel 9

Aaron Ji
5 min readJul 7, 2023

--

Photo by Ben Griffiths on Unsplash

Laravel provides several built-in user providers for authentication, including Eloquent and Database providers. However, sometimes you may want to use a custom data source or storage for user authentication. In such cases, you can create a custom user provider in Laravel.

For my case, our client has already had hash algorithm and function to work, I’m thinking how to use Laravel 9 to do same thing.

So in this tutorial, we will walk you through the steps of creating a custom user provider in Laravel.

Prerequisites

Before we get started, make sure you have the following:

- Laravel installed on your machine

- A database setup for your Laravel application

Step 1: Create the User Model

The first step is to create a User model that extends the `Illuminate\Database\Eloquent\Model` class and implement the `Illuminate\Contracts\Auth\Authenticatable` interface. This model will be used to retrieve user information from the database.

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use HasFactory;
public $table='cms_adminaccount';
protected $primaryKey = 'uid';
public $timestamps = false;
public $fillable = ['username', 'email', 'password'];
}

Step 2: Create the User Provider

The next step is to create a custom user provider that will handle user authentication. You can create a user provider using the `make:provider` Artisan command:

php artisan make:provider AdminUserProvider

This command will create a new file called `AdminUserProvider.php` in the `app/Providers` directory. Because we want to use Eloquent to fetch user from DB, but just change how it validates the password. So we extend the class `EloquentUserProvider`

<?php

namespace App\Providers;

use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;

class AdminUserProvider extends EloquentUserProvider
{
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(UserContract $user, array $credentials): bool
{
if (is_null($plain = $credentials['password'])) {
return false;
}

return $this->hasher->check($plain, $user->getAuthPassword(), ['salt' => $user->salt]);
}
}

The `retrieveById` method in the parent class should retrieve a user by their unique identifier, which is typically the user ID. But pay attention to some DB design may choose for example `uid` as the primary key. So then you need to add `protected $primaryKey = ‘uid’;` in your `User` model.

The `retrieveByCredentials` method in the parent class should retrieve a user by their credentials (e.g., email and password).

The `validateCredentials` method should validate the user’s credentials. This is the methond we want to extend and put in our logic.

Step 3: Register the User Provider

After creating the custom user provider, you need to register it with Laravel. To do this, open the `config/auth.php` file and add your provider to the providers array:

'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admin_provider' => [
'driver' => 'admin_provider_driver',
'model' => App\Models\Admin::class,
],
],

In this example, we’ve added a new provider named `admins` and set its driver to `admin_driver`. The model key specifies the custom user model that we created in Step 1.

Note that you can choose any name for your provider and driver. It’s common to name them after your application or the type of user they represent.

Step 4: Register the custom guard

Define your guard in the guards array of the `config/auth.php` file. We want to use the admin guard to authenticate admin users.

    'guards' => [
'admin' => [
'driver' => 'session',
'provider' => 'admin_provider',
]
],

Step 5: Register custom provider in AuthServiceProvider

In the `boot` method of the `AuthServiceProvider`, register the custom user provider using the `Auth` facade:

    public function boot()
{
$this->registerPolicies();

// add custom guard provider
Auth::provider('admin_provider_driver', function ($app, array $config) {
return new AdminUserProvider(new SimpleHasher(), $config['model']);
});
}

This code registers a new user provider named `admin_provider_driver` that uses the `AdminUserProvider` class. The second parameter passed to the `AdminUserProvider` constructor is the user model class, which is defined in the `config/auth.php` file.

The first parameter passed to the `AdminUserProvider` constructor is the custom hasher we created for checking user password.

Step 6: Create custom hasher

Because we just want to use the custom hasher for admin user, then we put this hasher in the `services` folder:

<?php

namespace App\Services;

use Illuminate\Contracts\Hashing\Hasher;
use Illuminate\Hashing\AbstractHasher;

class SimpleHasher extends AbstractHasher implements Hasher
{
public function make($value, array $options = [])
{
$salt = substr(uniqid(rand()), -6);

return md5(md5($value) . $salt);
}

public function check($value, $hashedValue, array $options = [])
{
return md5(md5($value) . $options['salt'] ?? '') === $hashedValue;
}

public function needsRehash($hashedValue, array $options = [])
{
// Your needsRehash implementation here
}
}

in our case we need to use extra info in the `$options` array to check the password, so this is why we extend `EloquentUserProvider` to have our custom `AdminUserProvider` which in the `validateCredentials` function passes the extra info for checking.

Step 7: Create admin authenticate middleware to guard admin

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class AdminAuthenticate
{
public function handle($request, Closure $next)
{
if (Auth::guard('admin')->check()) {
return $next($request);
} else {
return redirect()->route('admin.login');
}
}
}

You then need to register this middle in the `Kernel.php`

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{

protected $routeMiddleware = [
'admin.auth' => \App\Http\Middleware\AdminAuthenticate::class,
];
}

Step 8: Set admin authenticate middleware in the controller

You could add `admin.auth` middleware for this controller or add in the routes for a group of controllers.

<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use function view;

class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('admin.auth');
}
}

Step 9: Authenticate admin user

You can use `Auth::guard(‘admin’)->attempt` to login admin user now.

    public function login()
{
if (request()->method() == 'POST') {
// validation

$credentials = request()->only('username', 'password');
if (Auth::guard('admin')->attempt($credentials)) {
return redirect()->route('admin.index');
} else {
return redirect()->back()->withErrors([
'email' => 'Invalid credentials',
]);
}
}

return view('admin.login');
}

Conclusion

Creating a custom user provider in Laravel is a simple process that allows you to customize the way that users are authenticated in your application. By following the steps outlined in this article, you can create a custom user provider that uses a slight different way to validate password.

--

--

Aaron Ji

Diligent software engineer with 10+ years experience in commercial application development with a real appetite for learning and growing.