PHP code example of jekk0 / jwt-auth

1. Go to this page and download the library: Download jekk0/jwt-auth library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

jekk0 / jwt-auth example snippets


// app/Http/Controllers/UserAuthController.php


namespace App\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class UserAuthController
{
    public function login(Request $request): JsonResponse
    {
        $credentials = $request->only('email', 'password');

//        $tokens = auth('jwt-user')->attempt($credentials);
//        if (is_null($tokens)) {
//            throw new AuthenticationException();
//        }

        $tokens = auth('jwt-user')->attemptOrFail($credentials);

        return new JsonResponse($tokens->toArray());
    }

    public function refresh(Request $request): JsonResponse
    {
        $tokens = auth('jwt-user')->refreshTokens((string)$request->get('token'));

        return new JsonResponse($tokens->toArray());
    }

    public function logout(): JsonResponse
    {
        auth('jwt-user')->logout();

        return new JsonResponse();
    }

    public function logoutFromAllDevices(): JsonResponse
    {
        auth('jwt-user')->logoutFromAllDevices();

        return new JsonResponse();
    }

    public function profile(Request $request): JsonResponse
    {
        return new JsonResponse(['name' => $request->user()->name, 'email' => $request->user()->email]);
    }
}


// routes/api.php



use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserAuthController;

Route::group(['prefix' => '/auth/user'], function () {
    Route::post('/login', [UserAuthController::class, 'login']);
    Route::post('/refresh', [UserAuthController::class, 'refresh']);
    Route::post('/logout', [UserAuthController::class, 'logout'])->middleware('auth:jwt-user');
    Route::post('/logout/all', [UserAuthController::class, 'logoutFromAllDevices'])->middleware('auth:jwt-user');
    Route::get('/profile', [UserAuthController::class, 'profile'])->middleware('auth:jwt-user');
});


// routes/console.php

use Illuminate\Support\Facades\Schedule;
use Jekk0\JwtAuth\Model\JwtRefreshToken;

Schedule::command('model:prune', ['--model' => [JwtRefreshToken::class]])->daily();

php artisan make:listener AccessTokenInvalidation



namespace App\Listeners;

use Illuminate\Auth\AuthenticationException;
use Jekk0\JwtAuth\Events\JwtAccessTokenDecoded;
use Jekk0\JwtAuth\Model\JwtRefreshToken;

class AccessTokenInvalidation
{

    public function handle(JwtAccessTokenDecoded $event): void
    {
        // Solution 1
        $accessTokenId = $event->accessToken->payload->getJwtId();
        $refreshToken = JwtRefreshToken::whereAccessTokenJti($accessTokenId)->first();

        if ($refreshToken === null) {
            throw new AuthenticationException();
        }
        
        // Solution 2
        // $refreshTokenId = $event->accessToken->payload->getReferenceTokenId();
        // $refreshToken = JwtRefreshToken::find($refreshTokenId);
        //
        // if ($refreshToken === null) {
        //     throw new AuthenticationException();
        // }

        // Solution 3
        // If you do not want to use a relational database, you can implement token invalidation using two events:
        // 1. On Logout (JwtLogout Event) – Store the access token in a blacklist for its remaining lifetime using a fast storage solution, such as Redis or MongoDB.
        // 2. On Token Decoding (JwtAccessTokenDecoded Event) – Check whether the token is in the blacklist before processing it.
    }
}

php artisan make:listener RefreshTokenCompromised



namespace App\Listeners;

use Illuminate\Support\Facades\Log;
use Jekk0\JwtAuth\Events\JwtRefreshTokenCompromised;
use Jekk0\JwtAuth\Model\JwtRefreshToken;

class RefreshTokenCompromised
{
    public function handle(JwtRefreshTokenCompromised $event): void
    {
        Log::info("Guard $event->guard: Refresh token compromised.");

        // Get all user refresh tokens
        $affectedRefreshTokens = JwtRefreshToken::where('subject', '=', (string)$event->user->id)->get();

        // If you use Access token invalidation then this step is not needed
        foreach ($affectedRefreshTokens as $refreshToken) {
            $accessTokenId = $refreshToken->access_token_jti;

            // Invalidate access tokens
            // ...
        }

        // Invalidate refresh tokens related to user
        JwtRefreshToken::whereIn('jti', $affectedRefreshTokens->pluck('jti'))->delete();

        // Send notification to user
        //...
    }
}

// file app/Models/User.php 


namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Jekk0\JwtAuth\Contracts\CustomClaims;

class User extends Authenticatable implements CustomClaims
{
    // ...
    
    public function getJwtCustomClaims(): array
    {
        return [
            'role' => 'user',
            'name' => 'John'
        ];
    }
}

//...
// Get custom claims in controller 

$role = auth('jwt-user')->getAccessToken()->payload['role']
$name = auth('jwt-user')->getAccessToken()->payload['name']

// file /app/Providers/CustomJwtTokenExtractor.php



namespace App\Providers;

use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use Jekk0\JwtAuth\Contracts\TokenExtractor;

class CustomJwtTokenExtractor extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(TokenExtractor::class, function () {
            return new class implements TokenExtractor {
                public function __invoke(Request $request): ?string
                {
                    return $request->header('X-API-TOKEN');
                }
            };
        });
    }
    
    public function boot(): void
    {
        //
    }
}

// file /app/Providers/CustomJwtTokenIssuer.php



namespace App\Providers;

use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use Jekk0\JwtAuth\Contracts\TokenIssuer;

class CustomJwtTokenIssuer extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(TokenIssuer::class, function () {
            return new class implements TokenIssuer {
                public function __invoke(Request $request): string
                {
                    return 'CustomIssuer';
                }
            };
        });
    }
    
    public function boot(): void
    {
        //
    }
}


public function test_authenticate_in_tests(): void
{
    $user = UserFactory::new()->create();
    $response = $this->actingAs($user, 'YOUR-GUARD-NAME')->postJson('/api/profile');

    self::assertSame(200, $response->getStatusCode());
}

public function test_logout(): void
{
    $user = UserFactory::new()->create();
    auth('user')->login($user);
    
    $response = $this->postJson('/api/logout');
    self::assertSame(200, $response->getStatusCode());
}

public function test_logout(): void
{
    $user = UserFactory::new()->create();
    $tokenPair = auth($guard)->login($user);

    $response = $this->getJson('/api/profile', ['Authorization' => 'Bearer ' . $tokenPair->access->token]);    

    self::assertSame(200, $response->getStatusCode());
}

public function test_authenticate(): void
    {
        $user = UserFactory::new()->create();
        $accessToken = $this->app->get(TokenManager::class)->makeTokenPair($user)->access;
        
        $response = $this->postJson(
            '/api/profile',
            ['origin' => config('app.url')],
            ['Authorization' => 'Bearer ' . $accessToken->token]
        );

        self::assertSame(200, $response->getStatusCode());
    }
shell
php artisan vendor:publish --provider=Jekk0\JwtAuth\JwtAuthServiceProvider
shell
php artisan migrate
shell
php artisan make:controller UserAuthController
shell
curl --location 'localhost:8000/api/auth/user/profile' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
shell
curl --location --request POST 'localhost:8000/api/auth/user/logout' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
shell
curl --location --request POST 'localhost:8000/api/auth/user/logout/all' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
shell
php artisan make:provider CustomJwtTokenExtractor
shell
php artisan make:provider CustomJwtTokenIssuer