JWT (JSON Web Token) auth is for stateless clients — a mobile app or a separate SPA frontend calling your Laravel API — where there's no shared session cookie between client and server. If you're building a normal server-rendered Laravel app, Laravel's built-in session-based auth is simpler and more secure; JWT solves a problem that setup doesn't have.
1. Install the package
composer require tymon/jwt-auth
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret
jwt:secret generates and sets JWT_SECRET in your .env — this is the signing key for every token; treat it with the same care as APP_KEY.
2. Configure the User model
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims(): array
{
return [];
}
}
3. Set the guard
In config/auth.php, point the api guard's driver to jwt:
'guards' => [
'api' => ['driver' => 'jwt', 'provider' => 'users'],
],
4. Issue a token on login
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (! $token = auth('api')->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return response()->json(['access_token' => $token, 'token_type' => 'bearer']);
}
5. Protect routes
Route::middleware('auth:api')->group(function () {
Route::get('/me', fn (Request $request) => $request->user());
});
Token expiry and refresh
Tokens expire (default 60 minutes, set via JWT_TTL). Build a refresh endpoint rather than issuing very long-lived tokens — a stolen long-lived token is valid until it naturally expires, with no server-side way to revoke it early unless you also maintain a blocklist, which defeats much of the point of a stateless token.