PHP Laravel Restful API Authentication with JWT Token using Postman

In this post, you’ll learn how to use JWT (JSON Web Token) to authenticate a user in laravel Application. Topics such as setting up API, user registration, login and refreshing tokens by providing the old token.

Create a New Project

First, let us start by creating a project using the below command.

composer create-project --prefer-dist laravel/laravel laravel_jwt_app

Laravel will auto-detect the PHP version and will download compatible laravel version. You can also have a choice to specifically tell composer which version of laravel application to download using below command.

composer create-project --prefer-dist laravel/laravel laravel_jwt_app "6.*"

Adding "6.*" at the end will download laravel version 6.x.

Provide adequate permissions

If you are on Linux/ubuntu than provide permissions to apache server to access your application using below command.

sudo chmod -R 777 laravel_jwt_app

Database Setup

In .env connect the application to the database.

DB_DATABASE=laravel_jwt_app
DB_USERNAME=root
DB_PASSWORD=

Make Database Migration

Use below command to migrate schema to database.

php artisan migrate

After running migration command you’ll see all the schema is migrated to the database. And if you navigate to PHPMyAdmin your database looks like below.

Laravel - Database migration

Installing JWT (JSON Web Token)

Type below command in terminal and after few minutes you would notice tymon/jwt-auth package getting installed.

composer require tymon/jwt-auth

For official documentation, you can visit  JWT-auth laravel installation.

In config/app.php you must add Tymon\JWTAuth\Providers\LaravelServiceProvider::class in providers and also add JWT alias in aliases section.

'providers' => [
    ...
    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]

... 

'aliases' => [
    ...
    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
    'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
]

Now publish the package using below command. This will create a jwt.php file in config/jwt.php.

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

Now to create a secret key use below command.

php artisan jwt:secret

The jwt:secret will add a secret key to .env file.

JWT_SECRET=M9Aq8hKlqo5vkLFWo8AzZuzIq4ary0cGmm2ASrxXXVk7CzuW4qaxO1RoCsHKu1rV

Udemy Laravel Course for Beginners
Udemy Laravel Course for Beginners

Update User Model

Few changes must be done to user model and you have to implement JWTSubject and add two methods they are : getJWTIdentifier() and getJWTCustomClaims().

<?php

namespace App;

use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    // Rest omitted for brevity

    /**
        * 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 [];
    }
}

Setup Auth Guard

In config/auth.php you have to specify which auth guard application must use. In our case, we use API as auth guard which inturn uses JWT the driver.

'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],

'guards' => [
    ...
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

Create JWTAuthController

Now create a controller to set up login and registration for application.

php artisan make:controller JWTAuthController

Add basic auth methods in JWTAuthController

The basic methods JWTAuthController are :

  • login: Which will check for valid email and password. On authentication will return token
  • register: Will create a new user and return a user object.
  • me: This will return the user object in exchange of bearer token.
  • logout: Logouts the bearer token and will not be valid after log out to be used again.
  • refresh: Generates new bearer token in exchange for an old expired token.
  • respondWithToken: Returns token with expiration information.
  • guard: Returns details respective of auth guard used in our case it is jwt.
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class JWTAuthController extends Controller
{
     /**
        * Get a JWT token via given credentials.
        *
        * @param  \Illuminate\Http\Request  $request
        *
        * @return \Illuminate\Http\JsonResponse
        */
    public function login(Request $request)
    {
        $credentials = $request->only('email', 'password');

        if ($token = $this->guard()->attempt($credentials)) {
            return $this->respondWithToken($token);
        }

        return response()->json(['error' => 'Unauthorized'], 401);
    }

    public function register(Request $request)
    {
        $query = [
            "name" => $request->name,
            "email" => $request->email,
            "password" => bcrypt($request->password),
        ];

        $user = User::create($query);

        return $user;
    }

    /**
        * Get the authenticated User
        *
        * @return \Illuminate\Http\JsonResponse
        */
    public function me()
    {
        return response()->json($this->guard()->user());
    }

    /**
        * Log the user out (Invalidate the token)
        *
        * @return \Illuminate\Http\JsonResponse
        */
    public function logout()
    {
        $this->guard()->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    /**
        * Refresh a token.
        *
        * @return \Illuminate\Http\JsonResponse
        */
    public function refresh()
    {
        return $this->respondWithToken($this->guard()->refresh());
    }

    /**
        * 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' => $this->guard()->factory()->getTTL() * 60
        ]);
    }

    /**
        * Get the guard to be used during authentication.
        *
        * @return \Illuminate\Contracts\Auth\Guard
        */
    public function guard()
    {
        return Auth::guard();
    }
}
    

Setting up of Routes

Start adding routes for a method in routes/api.php file.

Route::post('register', "JWTAuthController@register");
Route::post('login', "JWTAuthController@login");

Route::group([
    'middleware' => ['api', 'jwt.auth'],
], function ($router) {
    Route::post('logout', "JWTAuthController@logout");
    Route::post('refresh', "JWTAuthController@refresh");
    Route::post('me', "JWTAuthController@me");
});

Setup Custom Middleware to validate user

This is an additional step because in near future you may need a custom middleware insisted of using default JWT middleware.

php artisan make:middleware JwtMiddleware

Update JwtMiddleware, which checks token and if invalid the exceptions are thrown by JWTAuth::parseToken()->authenticate().
The catch is used to send proper exception message to the client based on the exception object.

<?php

namespace App\Http\Middleware;

use Closure;
use Exception;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

class JwtMiddleware
{
    /**
        * Handle an incoming request.
        *
        * @param  \Illuminate\Http\Request  $request
        * @param  \Closure  $next
        * @return mixed
        */
    public function __construct()
    {
        
    }

    public function handle($request, Closure $next)
    {
        try {
            $user = JWTAuth::parseToken()->authenticate();
        } catch (Exception $exception) {
            if ($exception instanceof TokenInvalidException){
                return response()->json(['status' => 'Token is Invalid']);
            }else if ($exception instanceof TokenExpiredException){
                return response()->json(['status' => 'Token is Expired']);
            }else if ($exception instanceof UnauthorizedHttpException || $exception instanceof TokenBlacklistedException){
                return response()->json(['status' => 'The token has been blacklisted']);
            }
        }
        return $next($request);
    }
}    

Add JwtMiddleware class to laravel_jwt_app/app/Http/Kernel.php below $routeMiddleware.

protected $routeMiddleware = [
    ...
    ...
    'jwt.auth' => App\Http\Middleware\JwtMiddleware::class, 
];

Modify Exception Handler for a proper error response message

This step is optional but you can also go ahead with modifying Handler.php.
In laravel_jwt_app/app/Exceptions/Handler.php

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

public function render($request, Exception $exception)
{
    if ($exception instanceof TokenInvalidException){
        return response()->json(['status' => 'Token is Invalid']);
    }else if ($exception instanceof TokenExpiredException){
        return response()->json(['status' => 'Token is Expired']);
    }else if ($exception instanceof UnauthorizedHttpException || $exception instanceof TokenBlacklistedException){
        return response()->json(['status' => 'The token has been blacklisted']);
    } 

    return parent::render($request, $exception);
}

Start Testing Api’s

New User Registration

Laravel JWT Token Authentication - Registering new user using Postnam API Client

Login registered user

Login newly registered user using Postnam API Client

Get user details using bearer token

Laravel JWT Token Authentication - retrieve user details by providing bearer token

A refresh token with the old token

Laravel JWT Token Authentication - Refreshing token using Postnam API Client

Retrieving user details through invalid token

Laravel JWT Token Authentication - trying to retrive user details by providing old or expired token

Conclusion

You have come to end of this post on PHP Laravel Restful API Authentication with JWT Token using Postman. Comment if you have any other questions to ask and we’ll definitely reach to you.

Related Posts

Summary
Review Date
Reviewed Item
PHP Laravel Restful Api Authentication with JWT Token using Postman
Author Rating
51star1star1star1star1star
Software Name
PHP Laravel Framework
Software Name
windows, max os and ubuntu
Software Category
Web Development