Are you looking to start building a project with backend laravel and send API requests using Rest API here is a good tutorial.
In this tutorial, I will build a simple backend project with laravel and Tymon JWT-auth.
Setup a Laravel Project using Composer
There are a few options when it comes to installing Laravel. We will be using Composer to setup the Laravel framework.
For this you will need to install the following:
Composer
Node
And for development, you will be needing PHP 8.
After installing all of this, we can simply run the following command to scaffold a complete Laravel project:
composer create-project Laravel/laravel laravel-jwt-rest-api
Setup a .env file database connexion
First, create a database by the same name of the project "laravel-jwt-rest-api", add connexion to .env file:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_jwt_rest_api
DB_USERNAME=root
DB_PASSWORD=
Now, Let's Install JWT Auth
composer require tymon/jwt-auth --ignore-platform-reqs
And you need to install laravel to generate jwt encryption keys. This command will create the encryption keys needed to generate secure access tokens:
php artisan jwt:secret
After successfully install laravel jwt, register providers. Open config/app.php . and put the bellow code :
'providers' => [
….
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
],
'aliases' => [
….
'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
],
JWT auth package comes up with middlewares that we can use. Register auth.jwt middleware in
app/Http/Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'jwtAuth' => \App\Http\Middleware\JWTMiddleware::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
Now we need to modify User model. Open App/Models/User.php file and implement Tymon\JWTAuth\Contracts\JWTSubject interface. We also need to add two model methods getJWTIdentifier() and getJWTCustomClaims().
<?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;
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
Next, the default authentication guard is web. We need to change it to api. Open config/auth.php file and change default guard to api.
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'hash'=>false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => 10800,
];
Add Authentication routes
We need to register authentication routes into routes/api.php file. Open the file and add below routes into it.
// user
Route::post('/login', [AuthController::class, 'login']);
Route::post('/register', [AuthController::class, 'register']);
Route::get('/logout', [AuthController::class, 'logout'])->middleware("jwtAuth");
Route::post('/refresh', [AuthController::class, 'refresh'])->middleware("jwtAuth");
Route::get('/user-profile', [AuthController::class, 'getUser'])->middleware("jwtAuth");
Create AuthController controller class
We have defined routes for authentication so far. We need to create a controller class to build application logic. The below Artisan command will generate a controller class at App/Http/Controllers/Api directory.
php artisan make:controller AuthController
In the controller class, add the methods as per routes.
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Validator;
use App\Models\User;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Symfony\Component\HttpFoundation\Response;
use Tymon\JWTAuth\Facades\JWTAuth;
class AuthController extends Controller
{
public $token = true;
public function register(Request $request)
{
$validator = Validator::make($request->all(),
[
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
'c_password' => 'required|same:password',
]);
if ($validator->fails()) {
return response()->json(['error'=>$validator->errors()], 401);
}
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
if ($this->token) {
return $this->login($request);
}
return response()->json([
'success' => true,
'data' => $user
], Response::HTTP_OK);
}
public function login(Request $request)
{
$input = $request->only('email', 'password');
$jwt_token = null;
if (!$jwt_token = JWTAuth::attempt($input)) {
return response()->json([
'success' => false,
'message' => 'Invalid Email or Password',
], Response::HTTP_UNAUTHORIZED);
}
return response()->json([
'success' => true,
'token' => $jwt_token,
'user'=> Auth::user(),
]);
}
public function logout(Request $request)
{
try {
JWTAuth::invalidate(JWTAuth::parseToken($request->token));
return response()->json([
'success' => true,
'message' => 'User logged out successfully'
]);
} catch (JWTException $exception) {
return response()->json([
'success' => false,
'message' => 'Sorry, the user cannot be logged out'
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
public function getUser(Request $request)
{
try{
$user = JWTAuth::authenticate($request->token);
return response()->json(['user' => $user]);
}catch(Exception $e){
return response()->json(['success'=>false,'message'=>'something went wrong']);
}
}
}
We have created methods for authenticating APIs for Login, Register, getUser, Token Refresh, and Logout routes.
Create JWTMiddleware controller class
We need to protect our routes before the user gets into the controllers, for that we need to create a middleware JWTMiddleware using the command :
php artisan make:middleware JWTMiddleware
The JWTMiddleware contains the verification of the Token sent with API.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
class JWTMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$message = '';
try {
// check validation of the token
JWTAuth::parseToken()->authenticate();
return $next($request);
} catch (\Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
$message = 'Token expired';
} catch (\Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {
$message = 'Invalid token';
} catch (\Tymon\JWTAuth\Exceptions\JWTException $e) {
$message = 'Provide token';
}
return response()->json(['success' => false, 'message' => $message]);
}
}
Do the migration
First, you need to create a database by the name laravel_jwt_rest_api,then run this command :
php artisan migrate
Test application in Postman
We have completed the application coding. Start the Laravel server using below Artisan command.
php artisan serve
For testing APIs, we will use Postman application. Postman is an API platform for building and using APIs. We will test all API. Lets start from register API.
Register API
All API routes are prefixed with api namespace. In the postman use http://127.0.0.1:8000/api/register API endpoint. Pass name, email, password and c_password parameters into request. You will get message and user details into response.
Login API
Use http://127.0.0.1:8000/api/login API endpoint with email password parameter with request. If the email and password matches with registered user, you will receive token json object into response
GetUser API
All JWTMiddleware middleware routes are protected with api guard. You need to pass access_token in Header as bearer token.
Logout API
To logout the user, you need to invalidate the current token. You can simply call auth()->logout() method to invalidate current access token. Once user, logged out, it can't access protected routes.
Conclusion
Eventually, our tutorial is over. We have learned how to implement JWT authentication in Laravel application. In the next tutorial, we will use JWT token for REST API.
I hope, this tutorial will help on your development. If you liked this tutorial, please consider to share with your friends.
Top comments (2)
Amazing content!
The middleware is ignoring the return value of authenticate(). This can result in a valid token without an identified user. If the 'sub' value in the token is incorrect or the user cannot be found, the token will still be valid, but methods like JWTAuth::user() will not work correctly.
To fix this, consider the return value of authenticate():
This ensures that the user is correctly identified and avoids issues when using user-related methods.
The custom jwt middleware was helpful.Thank you.