If you’re building a website or app that requires user authentication, you need a secure way to verify users and control what they can access. This is where JWT (JSON Web Token) comes in.
JWT stands for JSON Web Token. It is a secure, compact, and URL-safe way to transmit data between a client (browser/app) and a server.
🔹 Think of JWT like a digital passport ️. When you travel, immigration stamps your passport to confirm your identity. Similarly, when you log in, the server gives you a JWT, which acts as proof of who you are.
🔹 This token contains encoded information about the user, like their ID, role (admin/user), and permissions.
🔹 The best part? JWT is stateless—the server doesn’t need to store any session data! Instead, the client (browser or mobile app) keeps the token and sends it with every request.
* Traditional Authentication (Session-Based Login)
* JWT Authentication (Token-Based Login)
# JWT is commonly used in:
*️ REST APIs & Microservices
*️ Mobile & Web Apps
*️ Single Sign-On (SSO)
1. User Logs In
2. Server Creates a JWT
{
"user_id": 123,
"role": "admin",
"exp": 1700000000 // Expiration time
}
3. Client Stores the Token
4. Client Requests a Protected Resource
Authorization
header:GET /profile
Authorization: Bearer <your_jwt_here>
5. Server Verifies the JWT
6. Access Granted or Denied
A JWT has three parts, separated by dots (.
):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiJ9.s0m3s3cr3tk3y
1. Header (contains metadata)
{
"alg": "HS256", // Algorithm used to sign the token
"typ": "JWT" // Token type
}
2. Payload (contains user data)
{
"user_id": 123,
"role": "admin",
"exp": 1700000000
}
3. Signature (used to verify the token’s integrity)
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret_key
)
Laravel has built-in authentication, but if you want to use JWT for API authentication, you can use the tymon/jwt-auth
package.
First, install the JWT authentication package using Composer:
composer require tymon/jwt-auth
Then, publish the package configuration:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
This will create a config/jwt.php
file.
Now, generate a secret key:
php artisan jwt:secret
This will update your .env
file with a JWT_SECRET
key.
Modify config/auth.php
to use JWT as the default authentication guard for APIs.
Find this section:
'guards' => [
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
Change 'token'
to 'jwt'
like this:
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
Run this command to generate an AuthController
:
php artisan make:controller AuthController
Now, add the following methods to AuthController.php
:
Register User and Generate JWT
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Tymon\JWTAuth\Facades\JWTAuth;
class AuthController extends Controller
{
public function register(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6'
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = JWTAuth::fromUser($user);
return response()->json([
'user' => $user,
'token' => $token
]);
}
Login User and Generate Token
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'Invalid credentials'], 401);
}
return response()->json([
'token' => $token
]);
}
Get Authenticated User
public function userProfile()
{
return response()->json(auth()->user());
}
Logout User
public function logout()
{
auth()->logout();
return response()->json(['message' => 'Successfully logged out']);
}
Open routes/api.php
and add the following routes:
use App\Http\Controllers\AuthController;
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:api')->group(function () {
Route::get('/profile', [AuthController::class, 'userProfile']);
Route::post('/logout', [AuthController::class, 'logout']);
});
Open app/Http/Kernel.php
and register the JWT authentication middleware:
protected $routeMiddleware = [
'jwt.auth' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
];
Now, protect your API routes by adding middleware('jwt.auth')
:
Route::middleware(['jwt.auth'])->group(function () {
Route::get('/profile', [AuthController::class, 'userProfile']);
});
You can test JWT authentication using Postman or CURL.
POST http://yourdomain.com/api/register
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123"
}
Response:
{
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
},
"token": "your_jwt_token_here"
}
Login User
POST http://yourdomain.com/api/login
Content-Type: application/json
{
"email": "john@example.com",
"password": "password123"
}
Response:
{
"token": "your_jwt_token_here"
}
Access Protected Route (Profile)
GET http://yourdomain.com/api/profile
Authorization: Bearer your_jwt_token_here
Response:
{
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
If you’re using plain PHP, you can still implement JWT authentication using the firebase/php-jwt
package.
composer require firebase/php-jwt
Step 2: Generate JWT Token
use Firebase\JWT\JWT;
$secret_key = "your_secret_key";
$payload = [
"user_id" => 123,
"exp" => time() + (60 * 60) // Token expires in 1 hour
];
$token = JWT::encode($payload, $secret_key, 'HS256');
echo json_encode(["token" => $token]);
Step 3: Decode and Verify JWT Token
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$token = $_GET['token']; // Get token from request
try {
$decoded = JWT::decode($token, new Key($secret_key, 'HS256'));
echo json_encode($decoded);
} catch (Exception $e) {
echo json_encode(["error" => "Invalid token"]);
}
Feature | API Keys | JWT Authorization |
Purpose | Identifies the client, limits API usage. | Authenticates & authorizes the user. |
Format | Long string of characters. | Encoded JSON object. |
Security | Less secure, can be stolen easily. | More secure, digitally signed. |
Authentication | ❌ No authentication. | Used for authentication. |
Authorization | ❌ No authorization. | Used for authorization. |
Usage | Sent as a query parameter or header. | Sent as a Bearer token in the Authorization header. |
Flexibility | Limited | More flexible with access control. |
Standardization | No universal standard. | Follows the JWT standard. |
✅ Use HTTP-only cookies instead of local storage for security.
✅ Set expiration times (exp
) to prevent token misuse.
✅ Store JWT secret keys securely (in .env
file).
✅ Use refresh tokens for long-lived sessions.
✅ Limit token scope—store only necessary user data in the payload.
JWT is an efficient, scalable, and secure way to handle authentication and authorization in modern applications. It eliminates the need for server-side session storage and works perfectly in microservices, APIs, and mobile apps.
If you’re building a secure login system, an API, or a scalable web app, JWT is the way to go!
Subscribe to get the latest posts sent to your email.