vkoori / laravel-stateless-auth
Stateless authentication for Laravel using JWT (JSON Web Tokens). This package enables secure, token-based authentication for API endpoints.
Requires
- php: ^8.1
- vkoori/laravel-jwt: ^0.1
Requires (Dev)
- laravel/framework: ^8.0|^9.0|^10.0|^11.0|^12.0
README
A fully stateless JWT authentication guard and provider for Laravel.
Supports access/refresh tokens, automatic cookie injection, multi-source token parsing (header, query, cookie), and token revocation.
β¨ Features
- π Custom Laravel guard + provider (fully stateless)
- β»οΈ Refresh token support
- πͺ Cookie-based tokens (HttpOnly, optional)
- π© Header / Query string token support
- π Token revocation
- π‘ Simple trait-based token issuing
- β‘οΈ Octane-ready
π¦ Installation
composer require vkoori/laravel-stateless-auth
βοΈ Configuration
Publish the config file:
php artisan vendor:publish --provider="Vkoori\JwtAuth\AuthServiceProvider"
This will publish config/jwt-guard.php
.
also read optionally
π‘ Register the Guard & Provider
In your config/auth.php
:
'guards' => [ 'api' => [ 'driver' => 'jwt-auth', 'provider' => 'jwt-users', ], ], 'providers' => [ 'jwt-users' => [ 'driver' => 'jwt-auth-provider', 'model' => App\Models\User::class, ], ],
π€ Token Support on User Model
Your User
model must use the provided trait:
use Vkoori\JwtAuth\Auth\Traits\HasApiTokens; class User extends Authenticatable { use HasApiTokens; }
π§© Custom Cache Driver for JWT Token Storage
To prevent JWT tokens from being removed during global cache clears (php artisan cache:clear
), you can isolate token storage using a custom cache store.
π§ Configuration
Use one of the existing cache stores, or define a dedicated store for JWT.
- Add a new cache store in
config/cache.php
:
'stores' => [ // Other cache stores... 'redis_jwt' => [ 'driver' => 'redis', 'connection' => env('REDIS_JWT_CONNECTION', 'jwt'), 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), ], ],
- Define a dedicated Redis connection in
config/database.php
:
'redis' => [ // Other connections... 'jwt' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_JWT_DB', '2'), ], ],
- Set the custom driver on your
Authenticatable
model using theHasApiTokens
trait:
use Vkoori\JwtAuth\Auth\Traits\HasApiTokens; class User extends Authenticatable { use HasApiTokens; public ?string $jwtCacheDriver = 'redis_jwt'; }
π‘ Why This Matters
By using a dedicated Redis cache store for JWT tokens:
- php artisan cache:clear wonβt wipe out active tokens
- You can still manually clear tokens when needed:
php artisan cache:clear redis_jwt
This is especially useful when enable_revoke
is set to true
in your config, ensuring users are logged out securely while preserving system-wide cache stability.
π JWT Scope Middleware
This package includes a built-in JwtScopeMiddleware
to restrict route access based on scopes defined in the JWT token payload.
π§ Middleware Registration
β Laravel 12+
In Laravel 12+, middleware is registered using the bootstrap/app.php
:
->withMiddleware(function (Middleware $middleware): void { $middleware ->alias([ 'jwt.scope' => \Vkoori\JwtAuth\Middlewares\JwtScopeMiddleware::class, ]); })
π§± Laravel 11 and below
If you're using Laravel 11 or older, register the middleware in app/Http/Kernel.php
:
protected $routeMiddleware = [ // ... 'jwt.scope' => \Vkoori\JwtAuth\Middlewares\JwtScopeMiddleware::class, ];
β Defining Scopes in Your JWT
Make sure you include the scope
claim when generating your access tokens. Example:
$user->accessToken(scopes: ['admin', 'manager'])
π Protect Routes Using Scope Middleware
You can pass multiple allowed scopes or single scope, and access will be granted if at least one matches:
Route::middleware(['jwt.scope:admin'])->group(function () { Route::get('/admin/dashboard', [AdminController::class, 'index']); }); Route::middleware(['jwt.scope:admin,other'])->group(function () { Route::get('/admin/dashboard', [AdminController::class, 'index']); });
β οΈ Error Handling
- If the user is unauthenticated, a 401 Unauthorized will be thrown.
- If the token lacks the required scopes, a 403 Forbidden (ScopeException) will be raised.