Introduction
Laravel API authentication using JWT is a secure way to protect modern web applications and APIs.
Authentication is essential in modern web apps to protect user data and APIs.
Traditional session-based authentication can be limiting for stateless systems like APIs and SPAs.
JWT (JSON Web Token) offers a secure, scalable, stateless way to authenticate users without server-side sessions.
In this guide, you’ll learn how Laravel API authentication using JWT works, explore its advantages,
and implement it step by step to build secure and efficient REST APIs.
What is JWT?
JSON Web Token (JWT) is an open standard (RFC 7519) used for securely transmitting information between parties as a JSON object.
A JWT consists of three parts:
|
1 |
Header.Payload.Signature |
Example:
|
1 2 3 4 5 |
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . eyJzdWIiOiIxMjM0NTY3ODkwIn0 . dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U |
JWT Components
Header
Contains token metadata and signing algorithm.
|
1 2 3 4 |
{ "alg": "HS256", "typ": "JWT" } |
Payload
Contains claims and user-related information.
|
1 2 3 4 |
{ "sub": 1, "email": "user@example.com" } |
Signature
Used to verify the integrity of the token.
Why Use JWT Authentication?
JWT offers several advantages:
Stateless Authentication
No need to store session data on the server.
Scalability
Ideal for distributed systems and microservices.
Mobile-Friendly
Works seamlessly with Android and iOS applications.
Cross-Domain Support
Perfect for APIs consumed by multiple frontend applications.
Performance
Reduces database lookups and session management overhead.
Setting Up JWT Authentication in Laravel
Step 1: Install JWT Package
Laravel does not include JWT support by default, so install the popular package:
|
1 |
composer require tymon/jwt-auth |
Step 2: Publish Configuration
Generate the package configuration file:
|
1 |
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider" |
This creates:
|
1 |
config/jwt.php |
Step 3: Generate JWT Secret Key
Generate a secret key used to sign tokens:
|
1 |
php artisan jwt:secret |
A new entry will be added to your .env file:
|
1 |
JWT_SECRET=your_generated_secret_key |
Keep this key secure and never expose it publicly.
Configure the User Model
Update the User model to implement the JWTSubject interface.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php namespace App\Models; use Tymon\JWTAuth\Contracts\JWTSubject; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable implements JWTSubject { public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; } } |
Configure Authentication Guard
Update config/auth.php.
|
1 2 3 4 5 6 |
'guards' => [ 'api' => [ 'driver' => 'jwt', 'provider' => 'users', ], ], |
This tells Laravel to use JWT for API authentication.
Creating Authentication Endpoints
Create an authentication controller:
|
1 |
php artisan make:controller AuthController |
User Registration
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public function register(Request $request) { $validated = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users', 'password' => 'required|min:8|confirmed' ]); $user = User::create([ 'name' => $validated['name'], 'email' => $validated['email'], 'password' => bcrypt($validated['password']) ]); return response()->json([ 'message' => 'User registered successfully' ]); } |
User Login
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public function login(Request $request) { $credentials = $request->only('email', 'password'); if (!$token = auth('api')->attempt($credentials)) { return response()->json([ 'message' => 'Invalid credentials' ], 401); } return response()->json([ 'access_token' => $token, 'token_type' => 'Bearer', 'expires_in' => auth('api')->factory()->getTTL() * 60 ]); } |
Get Authenticated User
|
1 2 3 4 |
public function me() { return response()->json(auth('api')->user()); } |
Refresh Token
|
1 2 3 4 5 6 |
public function refresh() { return response()->json([ 'access_token' => auth('api')->refresh() ]); } |
Logout User
|
1 2 3 4 5 6 7 8 |
public function logout() { auth('api')->logout(); return response()->json([ 'message' => 'Successfully logged out' ]); } |
Define API Routes
Add routes in routes/api.php.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
use App\Http\Controllers\AuthController; Route::prefix('auth')->group(function () { Route::post('/register', [AuthController::class, 'register']); Route::post('/login', [AuthController::class, 'login']); Route::middleware('auth:api')->group(function () { Route::get('/me', [AuthController::class, 'me']); Route::post('/refresh', [AuthController::class, 'refresh']); Route::post('/logout', [AuthController::class, 'logout']); }); }); |
Protecting Routes
Any route can be protected using Laravel middleware.
|
1 2 3 4 5 6 7 |
Route::middleware('auth:api')->group(function () { Route::get('/profile', function () { return auth()->user(); }); }); |
Requests without a valid JWT token will receive a 401 Unauthorized response.
Sending JWT Token from Frontend
After login, store the token securely.
JavaScript Fetch Example
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'user@example.com', password: 'password' }) }); const data = await response.json(); localStorage.setItem('token', data.access_token); |
Authenticated Request
|
1 2 3 4 5 |
fetch('/api/auth/me', { headers: { Authorization: `Bearer ${localStorage.getItem('token')}` } }); |
Security Best Practices
1. Always Use HTTPS
JWT tokens should never be transmitted over unsecured HTTP connections.
2. Keep Token Expiry Short
Configure token lifetime in:
|
1 |
config/jwt.php |
Example:
|
1 |
'ttl' => 60 |
This expires tokens after 60 minutes.
3. Implement Token Refresh
Short-lived access tokens combined with refresh tokens improve security significantly.
4. Avoid Storing Sensitive Data
Never store passwords, personal information, or confidential business data inside JWT payloads.
5. Use Role-Based Claims
You can include user roles directly inside JWT claims.
|
1 2 3 4 5 6 |
public function getJWTCustomClaims() { return [ 'role' => $this->role ]; } |
This helps build authorization systems efficiently.
Common JWT Errors and Fixes
Token Expired
Error
|
1 |
TokenExpiredException |
Solution
Use the refresh endpoint to generate a new access token.
Token Not Provided
Error
|
1 |
Token not provided |
Solution
Ensure the request contains:
|
1 |
Authorization: Bearer YOUR_TOKEN |
Invalid Credentials
Error
|
1 |
Unauthorized |
Solution
Verify the email and password before generating the token.
Testing JWT Authentication
Example Laravel feature test:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public function test_user_can_login() { $user = User::factory()->create([ 'password' => bcrypt('password123') ]); $response = $this->postJson('/api/auth/login', [ 'email' => $user->email, 'password' => 'password123' ]); $response->assertStatus(200); } |
Testing ensures authentication continues to work correctly as your application evolves.
Conclusion
If you’re building a Laravel REST API, mastering JWT authentication is an essential skill that will help you create secure, production-ready applications.
Also you can hire laravel developers to customize this feature for your business needs.
Kindly explore our extensions.