JSON Web Token (JWT) authentication is used to verify ownership of JSON data, determining whether the data can be trusted. JWT is not encryption; it's an open standard enabling information to be securely transmitted between two parties as a JSON object, digitally signed using either a public/private key pair or a secret.

Laravel 11 JWT - Implementing RESTful APIs with JWT Authentication Tutorial

Table Of Content

1 Prerequisites

1.) PHP version of >= 8.2
2.) Composer
3.) Mysql

2 Introduction

In this article, we'll demonstrate the process of implementing JWT Authentication With Laravel 11. We will explore APIs, JWT, REST APIs, and Laravel JWT Authentication by building an example API.

3 Create / Install a Laravel Project

3.1 Install Laravel Project

First, ensure that your system has Composer installed. Run the following command to create a new Laravel project:

composer create-project laravel/laravel laravel11-jwt-app

Navigate to your project directory:

cd laravel11-jwt-app

3.2 Configure MySql Database

To configure the database, access the .env file to input and define your database credentials:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-jwt
DB_USERNAME=root
DB_PASSWORD=

4 Install Laravel api and and Update Authentication Exception

Laravel 11 doesn’t include an api.php route file by default. To install it, run:
    
        php artisan install:api
   
If the user is not authenticated, an exception will be triggered. Update the bootstrap/app.php file to handle this:
    
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        //
    })
    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->render(function (AuthenticationException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json([
                    'message' => $e->getMessage(),
                ], 401);
            }
        });
    })->create();

   

5 Install and set up JWT

We'll be using php-open-source-saver/jwt-auth to handle JWT Authentication With Laravel 11 as the original package tymondesign/jwt-auth is no longer maintained.

Install the package:

    
         composer require php-open-source-saver/jwt-auth
   
Publish the JWT configuration file:
    
    php artisan vendor:publish --provider="PHPOpenSourceSaver\JWTAuth\Providers\LaravelServiceProvider"
   
Generate a secret key to sign the JWT:
    
        php artisan jwt:secret
   
This will update the .env file with:
    
    JWT_SECRET=xxxxxxxx
    
Configure the auth.php file to use the JWT guard:
    
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],


    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

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

    ],
    

6 Modify the User model

To implement the PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject contract in your User model, update the app/Models/User.php file:
    
<?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 PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;


class User extends Authenticatable implements JWTSubject
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }
    /**
     * 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 [];
    }
}


7 Create Controller - AuthController

Generate a new controller to handle JWT-based authentication:
Use the following artisan command to Create Controller.

php artisan make:controller AuthController

Add the following methods: register, login, logout, me, and refresh.

Key Methods in JWTAuthController:

register(): Handles user registration by validating the input, creating a user, and generating a JWT token for the newly created user.

login(): Authenticates a user using email and password, and returns a JWT token if the credentials are valid.

me(): Retrieves the currently authenticated user by parsing the JWT token from the request.

logout(): Invalidates the JWT token, effectively logging the user out.


<?php
namespace App\Http\Controllers;
  
use App\Http\Controllers\Controller;
use App\Models\User;
use Validator;
  
  
class AuthController extends Controller
{
 
    /**
     * Register a User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function register() {
        $validator = Validator::make(request()->all(), [
            'name' => 'required',
            'email' => 'required|email|unique:users',
            'password' => 'required|confirmed|min:8',
        ]);
  
        if($validator->fails()){
            return response()->json($validator->errors()->toJson(), 400);
        }
  
        $user = new User;
        $user->name = request()->name;
        $user->email = request()->email;
        $user->password = bcrypt(request()->password);
        $user->save();

        $token = auth()->login($user);
        return response()->json([
            'status' => 'success',
            'message' => 'User created successfully',
            'user' => $user,
            'authorisation' => [
                'token' => $token,
                'type' => 'bearer',
                'expires_in' => auth()->factory()->getTTL() * 60
            ]
        ],200);
  
      //  return response()->json($user, 201);
    }
  
  
    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login()
    {
        $credentials = request(['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',
                    'expires_in' => auth()->factory()->getTTL() * 60
                ]
            ]);
  
      }
  
    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        return response()->json(auth()->user());
    }
  
    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();
  
        return response()->json([
            'status' => 'success',
            'message' => 'Successfully logged out',
        ]);
    }
  
    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return response()->json([
            'status' => 'success',
            'user' => auth()->user(),
            'authorisation' => [
                'token' => auth()->refresh(),
                'type' => 'bearer',
            ]
        ]);
    }
  
    /**
     * 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
        ]);
    }
}
?>

8 Define API Endpoints in routes/api.php

Define the API routes in the api.php file:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\TodoController;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');


Route::group([
    'middleware' => 'api',
    'prefix' => 'auth'
], function ($router) {
    Route::post('/register', [AuthController::class, 'register'])->name('register');
    Route::post('/login', [AuthController::class, 'login'])->name('login');
    Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:api')->name('logout');
    Route::post('/refresh', [AuthController::class, 'refresh'])->middleware('auth:api')->name('refresh');
    Route::post('/me', [AuthController::class, 'me'])->middleware('auth:api')->name('me');
});



9 Folder Structure

10 Run Laravel Server to Test the App

To test the Laravel REST API Authentication Using JWT, set the request header to Accept: application/json and include the JWT token as a Bearer token for authenticated routes. Start the server using:


Use the following artisan command to Test the App.

php artisan serve

11 Conclusion

Your Laravel 11 JSON Web Token (JWT) API Authentication is now fully set up.

Tags