Back to Blog
LaravelSep 5, 20267 min read

Laravel JWT Authentication: A Practical Setup Guide

Step-by-step guide to implementing JWT authentication in Laravel for API-based applications, including token generation, refresh tokens, and middleware protection.

Why JWT for Laravel APIs

When building APIs that serve both web and mobile clients, session-based auth doesn't scale well. JWT (JSON Web Tokens) provide stateless authentication — the server doesn't need to store session data.

I use JWT authentication in healthcare applications where patient data security is critical and the API serves multiple client types.

Installing the Package

The most common approach is using tymon/jwt-auth:

composer require tymon/jwt-auth
php artisan jwt:secret

User Model Setup

Your User model needs to implement the JWTSubject interface:

use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims()
    {
        return [];
    }
}

Authentication Controller

class AuthController extends Controller
{
    public function login(LoginRequest $request)
    {
        $credentials = $request->only('email', 'password');

        if (!$token = auth()->attempt($credentials)) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid credentials',
            ], 401);
        }

        return response()->json([
            'success' => true,
            'token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth()->factory()->getTTL() * 60,
            'user' => new UserResource(auth()->user()),
        ]);
    }

    public function me()
    {
        return new UserResource(auth()->user());
    }

    public function logout()
    {
        auth()->logout();
        return response()->json(['message' => 'Logged out']);
    }
}

Protecting Routes

Apply the JWT middleware to routes that require authentication:

Route::middleware('auth:api')->group(function () {
    Route::get('/me', [AuthController::class, 'me']);
    Route::post('/logout', [AuthController::class, 'logout']);
});

Token Refresh

Implement token refresh to avoid forcing users to log in repeatedly:

public function refresh()
{
    return response()->json([
        'token' => auth()->refresh(),
        'token_type' => 'bearer',
        'expires_in' => auth()->factory()->getTTL() * 60,
    ]);
}

Key Takeaways

  • JWT is stateless — no session storage needed on the server
  • Always implement token refresh for better UX
  • Use middleware to protect routes consistently
  • Store the secret key in `.env`, never in code
  • Consider token expiration based on your security requirements