Multi-User API Authentication Using Laravel JWT

Posted by Jino Antony on 2019-01-15

RESTful API development using Laravel is quite easy. Laravel provides built-in support for API development using Laravel Passport and a rich ecosystem with tons of packages makes development a breeze. Here we are going to use JWT for API authentication. JWT stands for JSON Web Tokens. You can read more about JWT here.

Getting Started

Let’s get started by installing a fresh Laravel application.

composer create-project --prefer-dist laravel/laravel multi-jwt-auth

For using JWT in laravel there is a popular package called jwt-auth created by Sean Tymon. Let’s install that package also.

composer require tymon/jwt-auth 1.0.*

Note: This article is only for Laravel version > 5.4 . You can read the full documentation here

Next, publish the config file using the command

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

This will publish a config file config/jwt.php that allows you to configure the basics of this package.

Now we need to set a secret key for the encryption and decryption of JWT tokens. For that run the below artisan command.

php artisan jwt:secret

This will update your .env file with something like JWT_SECRET=foobar

The Use Cases

We have 3 types of users.

  1. Admins

  2. Subadmins

  3. Users (Normal users)

Let’s create the migrations.

Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->timestamps();
});

Schema::create('admins', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->timestamps();
});

Schema::create('subadmins', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->timestamps();
});

Now run the migrations.

php artisan migrate

Create corresponding models.

<?php
namespace App;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
view raw User.php hosted with ❤ by GitHub

Note: Be sure to implement the JWTSubject contract.

Configuring the Auth Guard

jwt-auth works by extending laravel’s auth system. So we need to configure the auth guards.

Open config/auth.php and add these guards.

'guards' => [

    'admins' => [
        'driver' => 'jwt',
        'provider' => 'admins',
    ],

    'subadmins' => [
        'driver' => 'jwt',
        'provider' => 'subadmins',
    ],

    'users' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

Now let’s configure the provider details. Add these to the providers section.

'providers' => [

    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Admin::class,
    ],

    'subadmins' => [
        'driver' => 'eloquent',
        'model' => App\Subadmin::class,
    ],

    'users' => [
        'driver' => 'eloquent',
        'model' => App\User::class,
    ],
],

What is this guards Really? 😇

So let’s understand what these configurations imply.

Laravel uses guards for authentication. They define how the system should store and retrieve information about your users. We have defined 3 guards admins, subadmins, and users. Each guard has a driver and a model. The driver config tells the guard to use which method to authenticate users (usually session or api). The provider config indicates to which model the user is authenticated against and the driver used for the database connection. This is configured in the providers section.

You can also add more guards if you have more user hierarchies. If you need to know more about guards check out this blog.

Now let's configure the jwt settings. Open config/jwt.php and set the lock_user property to true.

'lock_subject' => true,

What this does is it instruct jwt to check if the user is authenticated against the correct table. This is done by adding a hash value of the table name to the generated token.

Now let’s create a custom middleware to instruct laravel to use the correct guard per route. Run the below artisan command to create a middleware.

php artisan make:middleware AssignGuard

<?php
namespace App\Http\Middleware;
use Closure;
class AssignGuard
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if($guard != null)
auth()->shouldUse($guard);
return $next($request);
}
}
view raw AssignGuard.php hosted with ❤ by GitHub

In order the middleware to work, we need to register it. For that, go to app/Http/Kernel.php and add the following to the $routeMiddleware array.

'assign.guard' => \App\Http\Middleware\AssignGuard::class,

Now add the middleware to the routes.

<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group(['prefix' => 'admin','middleware' => ['assign.guard:admins','jwt.auth']],function ()
{
Route::get('/demo','AdminController@demo');
});
Route::group(['prefix' => 'subadmin','middleware' => ['assign.guard:subadmins','jwt.auth']],function ()
{
Route::get('/demo','SubadminController@demo');
});
Route::group(['prefix' => 'user','middleware' => ['assign.guard:admins','jwt.auth']],function ()
{
Route::get('/demo','UserController@demo');
});
view raw api.php hosted with ❤ by GitHub

And that’s it. We have implemented multi-user authentication using jwt. If you have any queries feel free to ask in the comments section. Thank you.