DEV Community

Cover image for How to implement JWT in Laravel API
Germán Lozickyj
Germán Lozickyj

Posted on • Edited on

How to implement JWT in Laravel API

How to implement JWT Authentication.
Effortlessly Implementing it in Fast, Simple Steps.

After you have finished reading my post see my repo: jwt-auth-in-laravel

Table Of Contents

Install

  • Install package php-open-source-saver/jwt-auth
composer require php-open-source-saver/jwt-auth
Enter fullscreen mode Exit fullscreen mode
  • Run the following command to publish the package config file:
php artisan vendor:publish --provider="PHPOpenSourceSaver\JWTAuth\Providers\LaravelServiceProvider"
Enter fullscreen mode Exit fullscreen mode
  • I have included a helper command to generate a key for you:
php artisan jwt:secret
Enter fullscreen mode Exit fullscreen mode

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

It is the key that will be used to sign your tokens. How that happens exactly will depend on the algorithm that you choose to use.

Implementation

The implementation depends if you want to use algorithms of symmetric or asymmetric encryption

⚠️ If you want to implement the JWT authentication with a symmetric algorithm please scroll to code implementation ⚠️

Generate a certificate for asymmetric encryption

For generating certificates the command

php artisan jwt:generate-certs
Enter fullscreen mode Exit fullscreen mode

can be used. The .env file will be updated, to use the newly created certificates.

The command accepts the following parameters.

name description
force override existing certificates
algo Either rsa or ec
bits Key length for rsa
curve Curve to be used for ec
sha Hashing algorithm
passphrase Passphrase for the cert
dir Folder to place the certificates

Examples

Generating a 4096-bit rsa certificate with sha 512

php artisan jwt:generate-certs --force --algo=rsa --bits=4096 --sha=512
Enter fullscreen mode Exit fullscreen mode

Generating an ec certificate with prime256v1-curve and sha 512

php artisan jwt:generate-certs --force --algo=ec --curve=prime256v1 --sha=512
Enter fullscreen mode Exit fullscreen mode

After you have chosen the encryption algorithms with PUBLIC AND PRIVATE KEY.
Your .env file has to look like this:


JWT_PRIVATE_KEY=file://../storage/certs/jwt-ec-4096-private.pem
JWT_PUBLIC_KEY=file://../storage/certs/jwt-ec-4096-public.pem

code implementation

  • First You must add in config/auth.php the guard of JWT
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],
Enter fullscreen mode Exit fullscreen mode
  • Your User model has to look like this:

namespace App\Models;

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;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function getJWTCustomClaims()
    {
        return [];
    }

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }
}
Enter fullscreen mode Exit fullscreen mode
  • You have to create the routes for the AuthJwtController in your routes/api.php file
use App\Http\Controllers\ApiController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthJwtController;

Route::controller(AuthJwtController::class)->group(function () {
    Route::post('login', 'login');
    Route::post('refresh', 'refresh');
    Route::post('blacklist', 'blacklist');
    Route::post('logout', 'logout');
    Route::get('get-token/{user_id}', 'getTokenByUser');
});
Enter fullscreen mode Exit fullscreen mode
  • You have to add yours private endpoints in the middleware auth:jwt, like this:

Route::controller(ApiController::class)->middleware('auth:api')->group(function () {
    Route::get('private-endpoint', 'privateEndopint');
});
Enter fullscreen mode Exit fullscreen mode
  • You can configure the time of expiration of the tokens by adding this to the .env file
JWT_TTL=60
Enter fullscreen mode Exit fullscreen mode

You can see more configurations in config/jwt.php file

  • Finally, you have to create the AuthJwtController


use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;

class AuthJwtController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login']]);
    }

    public function login(Request $request): JsonResponse
    {
        $validate = Validator::make($request->all(), [
            'email' => 'required|string|email',
            'password' => 'required|string',
        ]);

        if ($validate->fails()) {
            return response()->json([
                'status' => false,
                'error_message' => $validate->errors(),
            ], 400);
        }

        $credentials = $request->only('email', 'password');
        $token = Auth::guard('api')->attempt($credentials);

        if (!$token) {
            return response()->json([
                'status' => false,
                'message' => 'Unauthorized',
            ], 401);
        }

        return response()->json([
            'status' => true,
            'authorisation' => [
                'token' => $token,
                'type' => 'bearer',
            ],
        ]);
    }

    //if you want use this methods for yourself, add role in your user model and you validate in this methods

    public function refresh(): JsonResponse
    {
        return response()->json([
            'status' => true,
            'authorisation' => [
                'token' => Auth::refresh(true),
                'type' => 'bearer',
            ],
        ]);
    }

    public function blackList(): JsonResponse
    {
        //if you want add to blacklist forever, pass true as parameter
        Auth::invalidate();

        return response()->json([
            'status' => true,
            'message' => 'token added to blacklist successfully'
        ], 200);
    }

    public function logout(): JsonResponse
    {
        Auth::logout();

        return response()->json([
            'status' => true,
            'message' => 'logout successfully'
        ], 200);
    }

    public function getTokenByUser(Request $request): JsonResponse
    {
        $validate = Validator::make(['user_id' => $request->user_id], [
            'user_id' => 'required',
        ]);

        if ($validate->fails()) {
            return response()->json([
                'status' => false,
                'error_message' => $validate->errors(),
            ], 400);
        }

        if (!Auth::tokenById($request->user_id)) {
            return response()->json([
                'status' => false,
                'error_message' => "There aren't Token with this user id",
            ], 400);
        }

        return response()->json([
            'status' => true,
            'token' => Auth::tokenById($request->user_id)
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

After you have completed the steps, You can use your JWT authentication in your Laravel app.

let's start to test the JWT authentication.

POSTMAN

When we are testing our private endpoints that have a middleware with JWT we should hit the /login endpoint with the credentials copy the token and then embed it in the baren token of our private endpoint that has the JWT middleware.

Don't worry about that, follow the following steps to automate a pre-request that sets the JWT token in the bearer token to our private endpoint.

  • First you must import the collection into your Postman app

Collection Link

  • Import the environment in your Postman app

Environment Link

  • You have to select the environment imported
  • You have to create an endpoint inside of the collection imported and put the authorization Bearer Token like this:

Implement bearer token in Postman request

Do you not know how to import environments and collections on Postman?

Don't worry, learn about that in the following links:

How to import a collection

How to import an environment

Top comments (0)