PHPackages                             kz370/jwt-auth - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. kz370/jwt-auth

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

kz370/jwt-auth
==============

Secure JWT access token + refresh token authentication for Laravel

1.0.0(5mo ago)119MITPHPPHP ^8.1

Since Jan 12Pushed 5mo agoCompare

[ Source](https://github.com/kz370/jwt-auth)[ Packagist](https://packagist.org/packages/kz370/jwt-auth)[ RSS](/packages/kz370-jwt-auth/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (3)Versions (2)Used By (0)

Laravel JWT Auth
================

[](#laravel-jwt-auth)

[![Latest Version on Packagist](https://camo.githubusercontent.com/a9ed80e65516eb380ba1f439bb43cd3d1de2d75bf40fd4ac08021f7660261027/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b7a3337302f6a77742d617574682e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kz370/jwt-auth)[![Total Downloads](https://camo.githubusercontent.com/5202f6c0043013e8724e1871e3aec11ccdb50d6dbb0a1d98444277dcf6387696/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6b7a3337302f6a77742d617574682e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kz370/jwt-auth)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![PHP Version](https://camo.githubusercontent.com/23d185d525f163fc848f019029815f96e8ef3ff225f3db81b14a9ed18339e74d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e302d626c75652e7376673f7374796c653d666c61742d737175617265)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/6f0b4d6e9696a42d6d055f72badaf933465b97fdb14d515249f24e0ee9accf7a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d25354531302e3025323025374325323025354531312e3025323025374325323025354531322e302d7265642e7376673f7374796c653d666c61742d737175617265)](https://laravel.com)

A sophisticated, secure, and developer-friendly JWT authentication package for Laravel. Designed with a dual-token architecture (Access + Refresh tokens) and advanced security features like automatic rotation and replay attack detection.

---

🚀 Key Features
--------------

[](#-key-features)

- **Dual-Token Architecture**: Implements short-lived Access Tokens for security and long-lived Refresh Tokens for a seamless user experience.
- **Secure Token Management**: All refresh tokens are hashed (SHA-256) before storage, ensuring data safety even in the event of a database compromise.
- **Automatic Token Rotation**: Implements a "sliding session" approach where a new refresh token is issued on every use, immediately invalidating the previous one.
- **Advanced Replay Detection**: Real-time monitoring of token families. If a previously used refresh token is re-submitted, the system detects a breach and revokes the entire token family.
- **Granular Device Control**: Native support for tracking, listing, and revoking specific device sessions from anywhere in your application.
- **Zero-Config Integration**: Drop-in replacement for standard Laravel guards (Sanctum/Passport).

---

📦 Installation
--------------

[](#-installation)

Install the package via Composer:

```
composer require kz370/jwt-auth
```

### 1. Run Migrations

[](#1-run-migrations)

The package requires specific tables to manage token families and device sessions.

```
php artisan migrate
```

### 2. Publish Configuration (Optional)

[](#2-publish-configuration-optional)

Customize the TTL (Time-To-Live), signing algorithm, and other settings:

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

### 3. Generate JWT Secret

[](#3-generate-jwt-secret)

Generate a secure signing key for your tokens. This will be added to your `.env` file:

```
php artisan jwt:secret
```

---

👨‍💻 User Model Setup
--------------------

[](#‍-user-model-setup)

To enable session management and token relationships on your User model, add the `HasJwtAuth` trait:

```
use Kz370\JwtAuth\Traits\HasJwtAuth;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasJwtAuth;

    // ...
}
```

This trait provides several helper methods:

- `$user->jwtTokens`: Get all active sessions.
- `$user->currentJwtToken()`: Get the session model for the current request.

---

🎭 Multi-Model &amp; Multi-Guard Support
---------------------------------------

[](#-multi-model--multi-guard-support)

The package is not limited to the `User` model. You can use it with any Eloquent model (Admins, Customers, etc.) and even manage multiple guards simultaneously.

### 1. Custom Model

[](#1-custom-model)

If you only use one model but it's not `App\Models\User`, update your `config/jwt-auth.php`:

```
'user_model' => App\Models\Admin::class,
```

### 2. Multiple Guards (e.g., User and Admin)

[](#2-multiple-guards-eg-user-and-admin)

If you need separate authentication for different tables, define them in `config/auth.php`:

```
// config/auth.php
'guards' => [
    'jwt' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
    'admin-jwt' => [
        'driver' => 'jwt',
        'provider' => 'admins',
    ],
],

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
    ],
],
```

Then protect your routes accordingly:

```
Route::middleware('auth:admin-jwt')->get('/admin/profile', ...);
```

### How it works

[](#how-it-works)

The package uses a **polymorphic relationship** in the database. Instead of a simple `user_id`, the tokens table contains:

- `authenticatable_id`: The ID of the record (e.g., 1).
- `authenticatable_type`: The class name of the model (e.g., `App\Models\Admin`).

This design ensures that sessions are perfectly isolated, even if two different models share the same ID.

> **Note:** Ensure every model used for authentication includes the `HasJwtAuth` trait.

---

⚙️ Configuration
----------------

[](#️-configuration)

### Automatic Guard Registration

[](#automatic-guard-registration)

The package automatically registers a `jwt` authentication guard. To use it as your default for API routes, update your `config/jwt-auth.php`:

```
// config/jwt-auth.php
'override_default_guard' => true,
```

---

🛡 Middleware Usage
------------------

[](#-middleware-usage)

The package provides two middlewares out of the box to help you secure your routes.

### 1. `jwt.auth`

[](#1-jwtauth)

Protects routes that require a valid Access Token. It automatically validates the JWT and sets the authenticated user for the request.

```
// routes/api.php
Route::middleware('jwt.auth')->get('/user', function (Request $request) {
    return $request->user();
});
```

### 2. `jwt.refresh`

[](#2-jwtrefresh)

Ensures that the request contains a `refresh_token`. Useful for specific refresh or logout endpoints.

```
Route::middleware('jwt.refresh')->post('/refresh', [AuthController::class, 'refresh']);
```

---

⚡ Integration with Existing Auth
--------------------------------

[](#-integration-with-existing-auth)

If you are migrating from **Laravel Sanctum** or **Passport**, you simply need to replace your token generation logic in your authentication controllers.

Find where you currently generate tokens (e.g., `$user->createToken(...)`) and replace it with the `JwtAuth` facade:

```
use Kz370\JwtAuth\Facades\JwtAuth;

public function login(Request $request)
{
    // ... your validation logic ...
    $user = User::where('email', $request->email)->first();

    // Replace $user->createToken('...')->plainTextToken with:
    // Simplified: IP and User-Agent are detected automatically
    // You can just pass the device name as a string:
    $tokens = JwtAuth::login($user, 'iPhone 15 Pro');

    // $tokens content: ['access_token', 'refresh_token', 'expires_in', ...]
    return response()->json($tokens);
}
```

This ensures that users transitioning to this package correctly adopt the new dual-token system without leaving behind outdated logic.

---

🛠 Usage
-------

[](#-usage)

### Authentication (The Facade)

[](#authentication-the-facade)

The `JwtAuth` facade is the primary entry point for all operations.

#### User Login (Credentials)

[](#user-login-credentials)

```
use Kz370\JwtAuth\Facades\JwtAuth;

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

    // Choose your preferred syntax:

    // 1. Fully Automatic (detects IP and UA, sets device to null)
    $tokens = JwtAuth::attempt($credentials);

    // 2. Simplified Device Name (detects IP and UA automatically)
    $tokens = JwtAuth::attempt($credentials, 'iPhone 15 Pro');

    // 3. Full Manual Control
    $tokens = JwtAuth::attempt($credentials, [
        'device_name' => 'MacBook Pro',
        'ip_address'  => '1.1.1.1'
    ]);

    if (!$tokens) {
        return response()->json(['error' => 'Unauthorized'], 401);
    }

    return response()->json($tokens);
}
```

#### Token Refresh

[](#token-refresh)

Exchange a refresh token for a brand new pair of tokens (rotates the family).

```
public function refresh(Request $request)
{
    $tokens = JwtAuth::refresh($request->refresh_token);

    if (!$tokens) {
        return response()->json(['error' => 'Invalid or expired token'], 401);
    }

    return response()->json($tokens);
}
```

#### Logout

[](#logout)

Invalidates the current refresh token and session. Returns `true` on success, or `false` if the token is invalid/expired.

```
public function logout(Request $request)
{
    $revoked = JwtAuth::logout($request->refresh_token);

    if (!$revoked) {
        return response()->json(['message' => 'Invalid or already revoked token'], 401);
    }

    return response()->json(['message' => 'Logged out successfully']);
}
```

---

📱 Device &amp; Session Management
---------------------------------

[](#-device--session-management)

Take full control of user sessions across multiple devices:

```
// List all active sessions for a user
$sessions = JwtAuth::getDevices($userId);

// Revoke a specific session
JwtAuth::revokeDevice($userId, $sessionId);

// Global Logout: Revoke all sessions for a user
JwtAuth::logoutAll($userId);

// Revoke all OTHER sessions (stay logged in on current device)
JwtAuth::logoutOthers($currentRefreshToken);
```

---

🔒 Security Design
-----------------

[](#-security-design)

### Family IDs &amp; Token Rotation

[](#family-ids--token-rotation)

Every login starts a "Token Family". When you refresh, the old refresh token is revoked, and a new one is issued within the same family.

### Replay Attack Protection

[](#replay-attack-protection)

If a used refresh token is ever presented again (indicating it was stolen and replayed), the package detects this immediately and **revokes every token in that family**, forcing the legitimate user to re-authenticate and securing the account.

---

🖥 Console Commands
------------------

[](#-console-commands)

CommandDescription`php artisan jwt:secret`Generates a 64-character secret key for JWT signing.`php artisan jwt:cleanup`Removes expired and revoked tokens from the database.*Recommendation: Schedule the cleanup command to run daily:*

```
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('jwt:cleanup')->daily();
```

---

📄 License
---------

[](#-license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance70

Regular maintenance activity

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

172d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/60678186?v=4)[khaledz370](/maintainers/khaledz370)[@khaledz370](https://github.com/khaledz370)

---

Top Contributors

[![kz370](https://avatars.githubusercontent.com/u/259349470?v=4)](https://github.com/kz370 "kz370 (5 commits)")

### Embed Badge

![Health badge](/badges/kz370-jwt-auth/health.svg)

```
[![Health](https://phpackages.com/badges/kz370-jwt-auth/health.svg)](https://phpackages.com/packages/kz370-jwt-auth)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k102.4M1.4k](/packages/spatie-laravel-permission)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M131](/packages/laravel-pulse)[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M345](/packages/psalm-plugin-laravel)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M131](/packages/roots-acorn)[hasinhayder/tyro

Tyro - The ultimate Authentication, Authorization, and Role &amp; Privilege Management solution for Laravel 12 &amp; 13

6783.6k6](/packages/hasinhayder-tyro)[api-platform/laravel

API Platform support for Laravel

58171.5k14](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
