Build JWT Authentication (Login and Signup) in Laravel 8 Application

A step-by-step guide on Laravel 8 JWT authentication, this tutorial you will learn how to securely log-in and sign-up in the Laravel application using Laravel REST API.

Representational state transfer is a software architectural style that defines a set of constraints to be used for creating Web services. Web services that conform to the REST architectural style, called RESTful Web services, provide interoperability between computer systems on the internet.
wikipedia

JWT stands for JSON Web Token; it is a feature of authenticating securely by making the authentic transfer between two web servers, which lets you safe access in a web or mobile application.

JSON Web Token is an Internet standard for creating data with optional signature and optional encryption whose payload holds JSON that asserts some number of claims. The tokens are signed either using a private secret or a public/private key.
wikipedia

Let us understand the JWT mechanism.

JSON Web Tokens has three parts, mainly separated by (.) Header, Payload, and Signature.

Regardless of its original long programmatic form, this is the typical pattern of JWT.

xxxxxxxxxxx.yyyyyyy.zzzzzzz

Header

The header is made of two parts, which is as follows:

  • Token type, which is JWT
  • Signing algorithm, such as HMAC SHA256 or RSA.
For example:
{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

The second part of the json web token is known as payload, which comprises claims. Claims are statements about the user, and it has three types, such as registered, public, and private claims.

Signature

The signature part is referred to as an encoded header, payload, and a secret; it is solely responsible for authenticating the message that wasn’t changed along the way.

Let us start creating Laravel 8 REST API for JWT authentication in Laravel application.

Create Laravel Application

Run artisan command to create a new Laravel application, ignore this step if app already installed.

composer create-project laravel/laravel laravel-jwt-authentication-example --prefer-dist

Adding Database Credentials

Add the database credentials such as database name, user name and password in .env file.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

Now, execute command to migrate default users table.

php artisan migrate

Install & Set Up JWT Auth Module

Run command to install JSON Web Token Authentication for Laravel.

composer require tymon/jwt-auth

Execute the below command in the console.

composer update

Open config/app.php file and register tymondesigns/jwt-auth package in providers as well as aliases.

'providers' => [
    ....
    ....
    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
],
'aliases' => [
    ....
    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
    'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
    ....
],

Next, publish the JWT auth package configuration with below command.

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

Eventually, you need to run a command from the console to generate a secret auth secret.

php artisan jwt:secret

Open the .env and go to absolute bottom and check the JWT secret auth key.

JWT_SECRET=secret_jwt_key

Create User Model

Open app/Models/User.php and add getJWTIdentifier and getJWTCustomClaims methods.

<?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',
    ];

    public function getJWTIdentifier() {
        return $this->getKey();
    }

    public function getJWTCustomClaims() {
        return [];
    }    
}

Update Auth Guard

Go to config/auth.php, change guard property of defaults array to 'api', then navigate to guards > api > driver property and change driver’s prop to 'jwt' instead of token.

<?php

return [

    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],


    'guards' => [
       ...
       ...

        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

Create Auth Controller

Go to console and execute the below command to create authentication controller.

 php artisan make:controller JwtAuthController

Open and add the below code in app/Http/Controllers/JwtAuthController.php.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Auth;
use Validator;
use App\Models\User;


class JwtAuthController extends Controller
{

    public function __construct() {
        $this->middleware('auth:api', ['except' => ['login', 'register']]);
    }

    /**
     * Get a JWT via given credentials.
    */
    public function login(Request $request){
    	$req = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required|string|min:5',
        ]);

        if ($req->fails()) {
            return response()->json($req->errors(), 422);
        }

        if (! $token = auth()->attempt($req->validated())) {
            return response()->json(['Auth error' => 'Unauthorized'], 401);
        }

        return $this->generateToken($token);
    }

    /**
     * Sign up.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request) {
        $req = 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($req->fails()){
            return response()->json($req->errors()->toJson(), 400);
        }

        $user = User::create(array_merge(
                    $req->validated(),
                    ['password' => bcrypt($request->password)]
                ));

        return response()->json([
            'message' => 'User signed up',
            'user' => $user
        ], 201);
    }


    /**
     * Sign out
    */
    public function signout() {
        auth()->logout();
        return response()->json(['message' => 'User loged out']);
    }

    /**
     * Token refresh
    */
    public function refresh() {
        return $this->generateToken(auth()->refresh());
    }

    /**
     * User
    */
    public function user() {
        return response()->json(auth()->user());
    }

    /**
     * Generate token
    */
    protected function generateToken($token){
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth()->factory()->getTTL() * 60,
            'user' => auth()->user()
        ]);
    }
}

Register Auth API Routes

Head over to routes/api.php file and register API routes for Laravel application, routes are powered by RouteServiceProvider within the group aligned with api middleware group.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\JwtAuthController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::group([
    'middleware' => 'api',
    'prefix' => 'auth'
], function ($router) {
    Route::post('/signup', [JwtAuthController::class, 'register']);
    Route::post('/signin', [JwtAuthController::class, 'login']);
    Route::get('/user', [JwtAuthController::class, 'user']);
    Route::post('/token-refresh', [JwtAuthController::class, 'refresh']);
    Route::post('/signout', [JwtAuthController::class, 'signout']);
});

Use Postman to Test Auth REST API

Go to console and execute below command:

php artisan serve

Postman is a hassle free app to test the REST APIs, you can download Postman from here.

Following are the REST APIs we built with additional layer of security through JSON Web Token.

MethodsEndpoints
POST/api/auth/signup
POST/api/auth/signin
GET/api/auth/user
POST/api/auth/token-refresh
POST/api/auth/signout

Register User in Laravel

Start the Postman app, set the HTTP method to POST, enter the API URL for registering the new user. Select Body from the tab options, within the form-data segment, enter name, email, password and password confirmation data and click on Send button. You will see the response coming from the server about signing up a new user; you can check that user in your database’s User table.

JWT Authentication in Laravel

Check Login Auth API

Add signin API to login the laravel app along with email and password in Postman app then click on send button. You will see the server response with user information, access_token, token_tupe and expires_in.

Laravel Login Auth API

Get User Profile with JWT Token

Next, set the API method to GET, head over to Authorization section, select Type to Bearer Token add the access token that we received after making the Signin request.

Get User Profile with JWT Token

Token Refresh API

Refresh JSON web token, enter the API in Postman app, paste the Bearer token within the Authorization section.

Laravel JWT Token Refresh

Test Sign-out API

Sign-out from Laravel app by destroying the JWT token.

Sign-out from Laravel

Summary

Now, you have a basic understanding of how to build basic authentication REST API and secure them with JSON web token. Also, how to test those auth REST API with Postman. I hope you would like this example.

Download Laravel 8 Authentication REST API code: https://github.com/remotestack377/LaravelJWTAuthenticationExample