makaveli/laravel-jwt-auth

JWT authentication for Laravel

Maintainers

Package info

github.com/Ma1kaveli/laravel-jwt-auth

pkg:composer/makaveli/laravel-jwt-auth

Statistics

Installs: 8

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

1.1.4 2026-03-28 11:32 UTC

This package is auto-updated.

Last update: 2026-03-28 11:33:01 UTC


README

Packagist Version Packagist Downloads License

🌍 Languages

Table of Contents

  1. Introduction
  2. Requirements
  3. Installation
  4. Configuration
  5. Core Components
  6. Database Schema
  7. Quick Start
  8. Integration with BaseRepository
  9. Extending the Package
  10. Console Commands
  11. Recommendations
  12. Useful Links

Introduction

makaveli/laravel-jwt-auth is a lightweight, self‑contained JWT authentication package for Laravel. It provides generation, verification, refresh, and blacklisting of JWT tokens without relying on external libraries like tymon/jwt-auth or firebase/php-jwt. The package supports multiple storage drivers for blacklisting (memory, Redis, database) and a variety of algorithms (HS256, RS*, ES*), making it both flexible and easy to integrate into any Laravel project.

Key features:

  • Generation of access/refresh token pairs.
  • Support for HS256 (default), RS*, ES* algorithms.
  • Automatic signature, header, and payload verification (exp, sub, name).
  • Token blacklisting on refresh/logout with configurable TTL.
  • Three storage drivers for blacklist: memory (Laravel array cache), redis, database.
  • Fully tested with PHPUnit + Orchestra Testbench.
  • Console commands to generate JWT secret and run migrations.
  • Simple configuration via config/jwt.php.

Requirements

  • PHP 8.2 or higher
  • Laravel 10.x, 11.x, or 12.x
  • Composer
  • (Optional) Redis extension or predis/predis for the redis driver
  • (Optional) Database driver for the database driver (SQLite, MySQL, etc.)

Installation

  1. Install the package via Composer:

    composer require makaveli/laravel-jwt-auth
  2. (Optional) Publish the configuration file to customize settings:

    php artisan vendor:publish --tag=jwt-config

    This will copy the configuration file to config/jwt.php.

  3. Run the package migrations (required only for the database driver):

    php artisan migrate

    The package automatically loads its migrations; you do not need to publish them.

Configuration

The configuration file config/jwt.php allows you to customize the following parameters:

Parameter Description Default
algo JWT algorithm (HS256, RS256, ES256, etc.) 'HS256'
private Secret key (or path to private key for RSA/ECDSA) env('JWT_SECRET', 'test-secret-key')
ttl Access token lifetime in minutes env('JWT_TTL', 60)
refresh_ttl Refresh token lifetime in minutes env('JWT_REFRESH_TTL', 120)
allow_infinite_ttl Allow infinite TTL (token never expires) false
infinite_ttl_fallback Fallback TTL in seconds if infinite is not allowed 31536000 (1 year)
sub_payload_field User model field used for the sub claim 'email'
name_payload_fields User model fields to include in the name claim ['name']
user_model User model class \Illuminate\Database\Eloquent\Model::class
token_storage.driver Blacklist storage driver (memory, redis, database) env('JWT_TOKEN_STORAGE_DRIVER', 'memory')
token_storage.storage_ttl Blacklist TTL in seconds env('JWT_BLACKLIST_STORAGE_TTL', 86400 * 7) (7 days)

Example configuration for production:

return [
    'algo'                 => env('JWT_ALGO', 'HS256'),
    'private'              => env('JWT_SECRET'),
    'ttl'                  => env('JWT_TTL', 15),
    'refresh_ttl'          => env('JWT_REFRESH_TTL', 10080),
    'allow_infinite_ttl'   => false,
    'infinite_ttl_fallback'=> 31536000,
    'sub_payload_field'    => 'email',
    'name_payload_fields'  => ['name', 'email'],
    'user_model'           => App\Models\User::class,
    'token_storage' => [
        'driver'       => env('JWT_TOKEN_STORAGE_DRIVER', 'redis'),
        'storage_ttl'  => env('JWT_BLACKLIST_STORAGE_TTL', 604800),
    ],
];

Recommended .env values:

JWT_ALGO=HS256
JWT_SECRET=your-very-long-random-secret
JWT_TTL=15
JWT_REFRESH_TTL=10080
JWT_TOKEN_STORAGE_DRIVER=redis
JWT_BLACKLIST_STORAGE_TTL=604800

Core Components

JWTAuth Trait

The main trait that provides high‑level methods for token operations. It can be used in any class (typically a service or controller). It internally uses the underlying services and repositories.

Methods:

  • fromUser($user): Generates an access/refresh token pair from a user model.
  • verify($token): Verifies a token and returns the payload (or an array with verify_fail flag).
  • refreshToken($refreshToken): Issues a new token pair using a valid refresh token.
  • logout($accessToken): Blacklists the access token.

Example:

use JWTAuth\JWTAuth;

class AuthService
{
    use JWTAuth;

    public function authenticate($credentials)
    {
        if (auth()->attempt($credentials)) {
            [$access, $refresh] = $this->fromUser(auth()->user());
            return compact('access', 'refresh');
        }
        return null;
    }
}

Actions

The Actions namespace contains classes for blacklist operations:

  • AddToBlacklist: Adds a token to the blacklist.
  • IsBlacklisted: Checks if a token is blacklisted.
  • RemoveExpired: Removes expired tokens from storage (used by the scheduled job).

Services

Services encapsulate the write operations:

  • BlacklistService: Manages blacklist writes (used by AddToBlacklist).

Repositories

Repositories handle read operations:

  • BlacklistRepository: Checks if a token is blacklisted (used by IsBlacklisted).

Helpers

Low‑level JWT helpers:

  • JWTSlice: Encodes and decodes the JWT structure (header, payload, signature).
  • JWTVerify: Verifies the signature and payload integrity.
  • JWTCoder: Handles encoding/decoding with the chosen algorithm.

Token Storage

The blacklist storage is abstracted behind TokenStorageInterface. Three implementations are provided:

Driver Storage Best for
memory Laravel ArrayStore Testing, development
redis Redis (setex + scan) Production (recommended)
database Table blacklisted_tokens When Redis is not available

Switching drivers is done via config/jwt.php or the environment variable JWT_TOKEN_STORAGE_DRIVER.

Database Schema

When the database driver is used, the package creates the table blacklisted_tokens (or the name defined in the migration) with the following structure:

Column Type Description
id bigint (PK) Auto‑increment ID
token string The JWT token (or its hash)
expires_at timestamp Token expiration time (used for cleanup)
created_at timestamp When it was blacklisted

The table is automatically created when you run the Laravel migrations.

Quick Start

1. Configure the package

Publish and edit config/jwt.php to set your secret, TTLs, and storage driver. Generate a strong secret:

php artisan jwt:secret

2. Create an authentication service

use JWTAuth\JWTAuth;
use App\Models\User;

class AuthService
{
    use JWTAuth;

    public function login($email, $password)
    {
        $user = User::where('email', $email)->first();
        if (!$user || !password_verify($password, $user->password)) {
            return null;
        }

        [$access, $refresh] = $this->fromUser($user);
        return compact('access', 'refresh');
    }
}

3. Use the tokens in your controller

class AuthController extends Controller
{
    protected $authService;

    public function __construct(AuthService $authService)
    {
        $this->authService = $authService;
    }

    public function login(Request $request)
    {
        $tokens = $this->authService->login($request->email, $request->password);
        if (!$tokens) {
            return response()->json(['message' => 'Invalid credentials'], 401);
        }
        return response()->json($tokens);
    }

    public function refresh(Request $request)
    {
        $newTokens = $this->authService->refreshToken($request->refresh_token);
        if (!$newTokens) {
            return response()->json(['message' => 'Invalid refresh token'], 401);
        }
        return response()->json($newTokens);
    }

    public function logout(Request $request)
    {
        $this->authService->logout($request->bearerToken());
        return response()->json(['message' => 'Logged out']);
    }
}

4. Protect routes with middleware

Create a middleware that verifies the access token and attaches the user to the request.

namespace App\Http\Middleware;

use Closure;
use JWTAuth\JWTAuth;

class JwtAuthMiddleware
{
    use JWTAuth;

    public function handle($request, Closure $next)
    {
        $token = $request->bearerToken();
        if (!$token) {
            return response()->json(['message' => 'Token missing'], 401);
        }

        $payload = $this->verify($token);
        if ($payload['verify_fail'] ?? false) {
            return response()->json(['message' => 'Invalid or expired token'], 401);
        }

        $request->merge(['jwt_user' => $payload['user']]);
        return $next($request);
    }
}

Integration with BaseRepository

While this package does not directly depend on makaveli/laravel-core, you can easily use it in your existing repository architecture. For example, you might inject the JWTAuth trait into a repository that handles authentication‑related data.

use JWTAuth\JWTAuth;

class AuthRepository
{
    use JWTAuth;

    public function createTokensForUser($user)
    {
        return $this->fromUser($user);
    }
}

This keeps the token logic inside the repository, following the same pattern as other makaveli packages.

Extending the Package

You can extend the package in several ways:

  • New storage driver: Implement JWTAuth\Interfaces\TokenStorageInterface and register it in TokenStorageFactory.
  • Different algorithm: Extend JWTSlice and JWTAlgo to support custom signing methods.
  • Custom payload fields: Override the getJWTPayload method in your own trait or service to add custom claims.
  • Audit logging: Use Laravel events or observers on the BlacklistedToken model (if using the database driver) to log token blacklist events.

Console Commands

Command Description
php artisan jwt:secret Generates a new random secret key and updates the .env file.
php artisan jwt:clear-tokens Removes expired tokens from the blacklist (should be scheduled daily).

To schedule the cleanup, add the following to App\Console\Kernel:

protected function schedule(Schedule $schedule)
{
    $schedule->command('jwt:clear-tokens')->daily();
}

Recommendations

  • Use a strong, random secret and rotate it occasionally.
  • Choose the appropriate storage driverredis is recommended for production, database if you don’t have Redis.
  • Keep access token TTL short (e.g., 15 minutes) for security, and refresh token TTL longer (e.g., 7 days).
  • Always validate the sub claim and compare it with the actual user in your database.
  • Implement token revocation (logout) by blacklisting the access token.
  • Schedule the token cleanup to keep your blacklist storage lean.

Useful Links