Secure Rest API with JWT Authentication in Laravel 8x
SON Web Tokens are an open, industry-standard RFC 7519 method for representing claims securely between two parties. In this article, I’m going to show how to secure Laravel APIs with JWT. I’m testing on Laravel 8.6.0.
Table of Contents
- Install Laravel and Basic Configurations
- Install JWT Package
- Modify User Model
- Config Auth Guard
- Create Controller
- Define API Routes
- Test API
Install Laravel and Basic Configurations
Each Laravel project needs this thing. That’s why I have written an article on this topic. Please see this part from here: Install Laravel and Basic Configurations.
After completing basic configuration, run the migration:
php artisan migrate
Install JWT Package
We’ll use tymon/jwt-auth package. Run this composer command to install this package:
composer require tymon/jwt-auth
You need to publish the config file for JWT using the following command:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
JWT tokens will be signed with an encryption key. Run this command to generate key:
php artisan jwt:secret
The key will be store in .env
file like:
JWT_SECRET=secret-key
Modify User Model
We need to define two methods in app/Models/User.php
file. The methods are getJWTIdentifier()
and getJWTCustomClaims()
. The user model needs to implement JWTSubject.
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Get JWT identifier.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
Config Auth Guard
We need to set JWT auth guard as API guard in config/auth.php
file.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => false,
],
],
Create Controller
Let’s create a controller named AuthController:
php artisan make:controller AuthController
Now open the controller from app\Http\Controllers and paste this code:
<?php
namespace App\Http\Controllers;
use Validator;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login', 'register']]);
}
/**
* Register a User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|between:2,100',
'email' => 'required|string|email|max:100|unique:users',
'password' => 'required|string|confirmed|min:6',
]);
if ($validator->fails()) {
return response()->json($validator->errors()->toJson(), 400);
}
$user = User::create(array_merge(
$validator->validated(),
['password' => bcrypt($request->password)]
));
return response()->json([
'message' => 'User successfully registered',
'user' => $user
], 201);
}
/**
* Get a JWT token via given credentials.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|email',
'password' => 'required|string|min:6',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
if (!$token = $this->guard()->attempt($validator->validated())) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
/**
* Get the authenticated User
*
* @return \Illuminate\Http\JsonResponse
*/
public function profile()
{
return response()->json($this->guard()->user());
}
/**
* Log the user out (Invalidate the token)
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout()
{
$this->guard()->logout();
return response()->json(['message' => 'Successfully logged out']);
}
/**
* Refresh a token.
*
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken($this->guard()->refresh());
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => $this->guard()->factory()->getTTL() * 60
]);
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\Guard
*/
public function guard()
{
return Auth::guard('api');
}
}
I’ve set some simple functions in the controller.
Define API Routes
Open routes/api.php file and define these routes:
<?php
use App\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'auth', 'middleware' => 'api'], function () {
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
Route::post('refresh', [AuthController::class, 'refresh']);
Route::get('profile', [AuthController::class, 'profile']);
Route::post('logout', [AuthController::class, 'logout']);
});
Test API
We’ve finished all tasks. Let’s open Postman and start testing our API.
Register:
Login: We need to pass the token as a header field "Authorization: Bearer Token"
.
Refresh Token:
Profile Data:
Logout:
The tutorial is over. You can download this project from GitHub. Thank you.
Md Obydullah
Software Engineer | Ethical Hacker & Cybersecurity...
Md Obydullah is a software engineer and full stack developer specialist at Laravel, Django, Vue.js, Node.js, Android, Linux Server, and Ethichal Hacking.