JWT (Json Web Token) is used to create the authentication between two parties client and server that means it creates a secure information transactions between two parties. In the process of php-open-source-saver/jwt-auth token it creates a token claims and generates a token behalf of these claims then it verify on each request before processing the activities on application whether its authenticated or not.
Laravel by default uses passport authentication for Rest APIs but we can override it in config file to use the jwt token. Jwt tokens are easy to use and can easily maintain the authenticity of request by JSON token in request.
JWT tokens are signed with HMAC algorithm or private/public key. JWT tokens contains main three parts Header, Payload, signature separated by DOT(.)
In this article of Implement JWT Auth in Laravel I will use PHP php-open-source-saver/jwt-auth package to create jwt token in laravel 9. This package has several methods to attempt, check , refresh and many more.
In this example we will create a simple example to create the json token the library and when a user send a request for login by sending username and password if authentication successful the we will create the token and response back with the token to access the server using auth token. Client can save token in local storage or cookies for later use.
Tokens are time based means token will expire after a time period but we can refresh the token regularly to use it for long time.
Let’s start the tutorial of Implement JWT Auth in Laravel 9 with simple step by step
Step 1: Create a fresh laravel project
Open a terminal window and type below command to create a new project
composer create-project --prefer-dist laravel/laravel blog
You can also read this to start with new project
Step 2 : Install the package
I assume the you have already installed the laravel and basic connection of it like database connection and composer.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-jwt
DB_USERNAME=root
DB_PASSWORD=
Now install the package using composer in laravel root directory, open the terminal in laravel root directory and run below command to install php-open-source-saver/jwt-auth the package. This package has good stars on github and has lot of fan base of artisans
composer require php-open-source-saver/jwt-auth
Step 3 : Publish Vendor and Generate Secret Key
Now, publish the configuration files of package
php artisan vendor:publish --provider="PHPOpenSourceSaver\JWTAuth\Providers\LaravelServiceProvider"
this will create a a file in config/jwt.php
where you can configure the jwt token configurations.
and generate token using below command
php artisan jwt:secret
this will update a key JWT_SECRET
in .env
file as below
JWT_SECRET=generated_token
Step 4 : Generate user migration
If you have just installed a fresh project then Create the default table of users
in database using the artisan command
php artisan migrate
Now, for an example to access the articles by only authenticated user so i am creating here a table using migration and then i am going to fill the data in it, so create model and migration
php artisan make:model Article -m
this will generate the model and migration file
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
use HasFactory;
}
and migration file database/migrations/timestamp_create_articles_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();;
$table->string('title');
$table->string('body')->nullable();
$table->string('image');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('articles');
}
}
and then migrate the migration
php artisan migrate
Step 5 : Configure AuthGuard
By default laravel uses its own auth for Rest APIs so we need to change the AuthGuard to Jwt in the config/auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
To
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
Here we changed default auth to api
and also added new guard
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
Step 6 : Update User Model
To use the jwt we need to implement two methods in app\Models\User.php
class and add getJWTCustomClaims()
and getJWTIdentifier()
so update the User model as following
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
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 [];
}
}
and also create a article table and migration so we can access the articles only after login
php artisan make:model Article -m
Above command will create two files one is migration and other one is model. open migration file which is located at database/migrations/timestamp_create_articles_table.php
and edit the schema as below
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();;
$table->string('title');
$table->string('body');
$table->timestamps();
});
}
Run migration using artisan command in command line
php artisan migrate
Output of above command
Migrating: 2021_11_27_112800_create_articles_table
Migrated: 2021_11_27_112800_create_articles_table (45.63ms)
Now create seeder in database/seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
// Import DB and Faker services
use Illuminate\Support\Facades\DB;
use Faker\Factory as Faker;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$faker = Faker::create();
for ($i=0;$i<=100;$i++) {
DB::table('articles')->insert([
'title' => $faker->name,
'body' => $faker->text,
'email' => $faker->email,
'updated_at' =>$faker->datetime,
'created_at' => $faker->datetime
]);
}
}
}
Run Seeder in command line
php artisan db:seed
Step 3 : Create controller
Let’s create a controller and add a methods login
, register
, refresh and logout
php artisan make:controller AuthController
and add the below code
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use App\Models\User;
class AuthController extends Controller
{
public function login(Request $request)
{
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
]);
$credentials = $request->only('email', 'password');
$token = Auth::attempt($credentials);
if (!$token) {
return response()->json([
'status' => 'error',
'message' => 'Unauthorized',
], 401);
}
$user = Auth::user();
return response()->json([
'status' => 'success',
'user' => $user,
'authorisation' => [
'token' => $token,
'type' => 'bearer',
]
]);
}
public function register(Request $request){
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6',
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = Auth::login($user);
return response()->json([
'status' => 'success',
'message' => 'User created successfully',
'user' => $user,
'authorisation' => [
'token' => $token,
'type' => 'bearer',
]
]);
}
public function logout()
{
Auth::logout();
return response()->json([
'status' => 'success',
'message' => 'Successfully logged out',
]);
}
public function refresh()
{
return response()->json([
'status' => 'success',
'user' => Auth::user(),
'authorisation' => [
'token' => Auth::refresh(),
'type' => 'bearer',
]
]);
}
public function articles(){
return response()->json([
'status' => 'success',
'data' => \App\Models\Article::paginate()
]);
}
}
Here in above code we have used four methods
Function login : It accepts email and password and if authentication successful then return the user with token.
Function register : To create a new user with email, name and password then response with token.
Function refresh : To refresh the old token.
Function logout : To invalidate the token and logout the user.
Function articles : List of articles with logined user.
Step 4: Create routes in routes/api.php
Create route to login, register, refresh and logout
routes/api.php
<?php
use App\Http\Controllers\ArticleController;
use App\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route;
Route::controller(AuthController::class)>group(function () {
Route::post('login', 'login');
Route::post('register', 'register');
});
Route::controller(AuthController::class)->middleware("auth:api")->group(function () {
Route::post('logout', 'logout');
Route::post('refresh', 'refresh');
Route::get('articles', 'articles');
});
I
Postman Screenshot:
Response without login:
Note : Make sure to pass header accept : application/json for proper json response in case of unauthntication.
Also Read : How to create multiple size thumbs from image in laravel 8 ?