JSON Web Token (JWT) is an open standard (open standard means anyone can use it without any restriction) RFC 7519 method which has been designed for representing claims securely between two parties. JWT is mainly used for verifying the requests between two parties or we can say for information exchange. JWT basically works on the public/private key pair. The information is digitally signed hence serves more security to the parties.
JWT is an encoded string which contains three parts: Header, Payload and Verify Signature. They are separated with a period. Following is a format of the JWT:
s1ksDk8sd2.sdpcSd79a1.sda81eq
This article contains steps of API authentication using JWT:
STEP BY STEP INSTRUCTIONS FOR TUTORIAL OF API AUTHENTICATION USING JSON WEB TOKEN (JWT)
- Step 1: Create fresh Laravel application
To create the latest version of Laravel application. Open the Terminal and run the following command:
composer create-project laravel/laravel jwt –prefer-dist
Now change Terminal working directory to project:
cd jwt
- Step 2: Install and configure JWT library
You can install the JWT library by using the following command:
composer require tymon/jwt-auth
Now register the library service provider to config/app.php file. Open the file and add the following into the providers array.
‘providers’ => [
….
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
],
Publish JWT config file using the following command into terminal:
vendor:command
php artisan vendor:publish –provider=”Tymon\JWTAuth\Providers\LaravelServiceProvider”
This will copy configuration file from vendor to config/jwt.php.
After this, we will be needing to generate a token secret. Therefore, run the following artisan command:
php artisan jwt:secret
A JWT token secret to .env file. will be created.
- Step 3: Configuration of database in .env file
To configure database connection. Open the .env file from the root directory and start changing below given database credentials with your MySQL.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=jwt
DB_USERNAME=root
DB_PASSWORD=secret
Laravel have users table by default to authenticate API. So migrate users table into database using the command bellow:
php artisan migrate
- Step 4: Update User model
Open App/Models/User.php file and implement Tymon\JWTAuth\Contracts\JWTSubject interface. Now add two model methods:
getJWTCustomClaims() and getJWTIdentifier().
<?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 Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
/**
* 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 [];
}
}
- Step 5: Configure default authentication guard
Open config/auth.php file and change default guard to api.
<?php
return [
‘defaults’ => [
‘guard’ => ‘api’,
‘passwords’ => ‘users’,
],
‘guards’ => [
‘web’ => [
‘driver’ => ‘session’,
‘provider’ => ‘users’,
],
‘api’ => [
‘driver’ => ‘jwt’,
‘provider’ => ‘users’,
],
],
];
- Step 6: Add Authentication routes
Now open the file and add following routes into it:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\JWTController;
Route::group([‘middleware’ => ‘api’], function($router) {
Route::post(‘/register’, [JWTController::class, ‘register’]);
Route::post(‘/login’, [JWTController::class, ‘login’]);
Route::post(‘/logout’, [JWTController::class, ‘logout’]);
Route::post(‘/refresh’, [JWTController::class, ‘refresh’]);
Route::post(‘/profile’, [JWTController::class, ‘profile’]);
});
- Step 7: Create JWTController controller class
The following Artisan command will generate controller class at App/Http/Controllers directory:
php artisan make:controller JWTController
Add the following methods as per routes in the controller class:
<?php
namespace App\Http\Controllers;
use Auth;
use Validator;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class JWTController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware(‘auth:api’, [‘except’ => [‘login’, ‘register’]]);
}
/**
* Register user.
*
* @return \Illuminate\Http\JsonResponse
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
‘name’ => ‘required|string|min:2|max:100’,
’email’ => ‘required|string|email|max:100|unique:users’,
‘password’ => ‘required|string|confirmed|min:6’,
]);
if($validator->fails()) {
return response()->json($validator->errors(), 400);
}
$user = User::create([
‘name’ => $request->name,
’email’ => $request->email,
‘password’ => Hash::make($request->password)
]);
return response()->json([
‘message’ => ‘User successfully registered’,
‘user’ => $user
], 201);
}
/**
* login user
*
* @return \Illuminate\Http\JsonResponse
*/
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
’email’ => ‘required|email’,
‘password’ => ‘required|string|min:6’,
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
if (!$token = auth()->attempt($validator->validated())) {
return response()->json([‘error’ => ‘Unauthorized’], 401);
}
return $this->respondWithToken($token);
}
/**
* Logout user
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth()->logout();
return response()->json([‘message’ => ‘User successfully logged out.’]);
}
/**
* Refresh token.
*
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth()->refresh());
}
/**
* Get user profile.
*
* @return \Illuminate\Http\JsonResponse
*/
public function profile()
{
return response()->json(auth()->user());
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
‘access_token’ => $token,
‘token_type’ => ‘bearer’,
‘expires_in’ => auth()->factory()->getTTL() * 60
]);
}
}
- Step 8: Test application in Postman
We have completed the application coding. Start the Laravel server using the below Artisan command:
php artisan serve
For testing APIs in postman, consider the following steps.
- Refresh Token API
You can refresh the current token with a new token using auth()->refresh() method.
- Register API
All API routes are prefixed with api namespace. In the postman use http://localhost:8000/api/register API endpoint. Pass name, email, password and password_confirmation parameters into request.
- Profile API
You need to pass access_token in Header as bearer token as all auth:api middleware routes have been protected with api guard
- Login API
Use http://localhost:8000/api/login API endpoint with email password parameter with request. You will be receiving token json object into response, if the password, email matches with registered user.
- Logout API
You need to invalidate the current token to logout current token. Simply call auth()->logout() method to invalidate the current access token. Once a user logged out, it can’t access protected routes.