Setup Laravel 9 with JWT-Authentification
Tags: laravel, beginners, api, jwt
Published: 2022-07-01 12:23:54

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.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1vqyo9lr3lk6sgtwbk08.png) 

## 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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5cd2jhzsw3e2sh029sil.png)

## GetUser API
All JWTMiddleware middleware routes are protected with api guard. You need to pass access_token in Header as bearer token.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/empygisb0z3cpr6dynr4.png)

 ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/61s910f6wkfdhjflflws.png)

## 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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahdvcc6jzb4dfbygxvd8.png)
  
## 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.