Laravel 9 REST API Development Using JWT Authentication

Reading Time: 13 minutes
6,112 Views

Inside this article we will learn one more important concept of laravel i.e Laravel 9 REST API Development Using JWT Authentication. This will be step by step guide to create restful services from scratch.

REpresentational State Transfer (REST) is an architectural style that defines a set of constraints to be used for creating web services. REST API is a way of accessing web services in a simple and flexible way without having any processing.

In this article we will create a secure set of rest apis using laravel using JWT auth. We will use a JWT package to implement the concept of JWT authentication.

What we will do in this article –

  • User Register API
  • Login API
  • Refresh Token API
  • Logout API
  • Create Todo API
  • List Todo API
  • Single Todo details API
  • Update Todo API
  • Delete Todo API

Above are the apis, we will create using jwt authentication.

Learn More –

Let’s get started.

Laravel Installation

Open terminal and run this command to create a laravel project.

composer create-project laravel/laravel myblog

It will create a project folder with name myblog inside your local system.

To start the development server of laravel –

php artisan serve

URL: http://127.0.0.1:8000

Assuming laravel already installed inside your system.

Create Database & Connect

To create a database, either we can create via Manual tool of PhpMyadmin or by means of a mysql command.

CREATE DATABASE laravel_app;

To connect database with application, Open .env file from application root. Search for DB_ and update your details.

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

Install And Configure Laravel JWT Auth

JSON Web Token (JWT) is an open standard (RFC 7519), and it represents a compact and self-contained method for securely transmitting information between parties as a JSON object.

Open project into terminal and run this command.

$ composer require php-open-source-saver/jwt-auth

Publish Provider

Back to project terminal and run this command.

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

Generate JWT Secret Keys

$ php artisan jwt:secret

It will generate few JWT secret keys and save into .env file. You should see these keys into .env file. These keys handle the token encryption.

JWT_SECRET=ncXDYGJAU30WPY09AgijRXRnFppA3MhZGCG3sDnYhxOCRuFbaXbkYUzvfxg1BmPF

JWT_ALGO=HS256

Configure AuthGuard

We need to make a few changes to configure Laravel to use the JWT AuthGuard to power the application authentication.

To configure guard, Open auth.php file from /config folder.

//...

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

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

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

//...

Update User Model

When we install laravel setup, by default we get a model User.php inside /app/Models folder.

use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject; // Add this

class User extends Authenticatable implements JWTSubject {}

Open User.php and update with this code.

<?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 PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * 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 [];
    }
}

Create Model & Migration For Todo

Open project into terminal and run this artisan command.

$ php artisan make:model Todo -m

-m to create migration file as well.

Above command will generate two files. One is Model and second is migration file.

Model – Todo.php inside /app/Models folder

Migration – 2022_03_20_040948_create_todos_table.php inside /database/migrations

Open Todo.php and write this code into it.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Todo extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'description'
    ];
}

Open Migration file 2022_03_20_040948_create_todos_table.php and write this code.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('description');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('todos');
    }
};

Run Migration

Back to terminal and run this command to migrate.

$ php artisan migrate

Create Controllers

Back to terminal and run these artisan commands to create.

Auth Api Controller

$ php artisan make:controller AuthController

This command will create a file AuthController.php inside /app/Http/Controllers folder.

Todo Api Controller

$ php artisan make:controller TodoController

This command will create a file TodoController.php inside /app/Http/Controllers folder.

Now, we will start writing code inside all these controllers.

Open AuthController.php file and write this code into it.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use App\Models\User;

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

    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required|string|email',
            'password' => 'required|string',
        ]);
        $credentials = $request->only('email', 'password');

        $token = Auth::attempt($credentials);
        if (!$token) {
            return response()->json([
                'status' => 'error',
                'message' => 'Unauthorized',
            ], 401);
        }

        $user = Auth::user();
        return response()->json([
            'status' => 'success',
            'user' => $user,
            'authorisation' => [
                'token' => $token,
                'type' => 'bearer',
            ]
        ]);
    }

    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 = Auth::login($user);
        return response()->json([
            'status' => 'success',
            'message' => 'User created successfully',
            'user' => $user,
            'authorisation' => [
                'token' => $token,
                'type' => 'bearer',
            ]
        ]);
    }

    public function logout()
    {
        Auth::logout();
        return response()->json([
            'status' => 'success',
            'message' => 'Successfully logged out',
        ]);
    }

    public function refresh()
    {
        return response()->json([
            'status' => 'success',
            'user' => Auth::user(),
            'authorisation' => [
                'token' => Auth::refresh(),
                'type' => 'bearer',
            ]
        ]);
    }
}

Open TodoController.php file and write this code into it.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Todo;

class TodoController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api');
    }

    public function index()
    {
        $todos = Todo::all();
        return response()->json([
            'status' => 'success',
            'todos' => $todos,
        ]);
    }

    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'required|string|max:255',
        ]);

        $todo = Todo::create([
            'title' => $request->title,
            'description' => $request->description,
        ]);

        return response()->json([
            'status' => 'success',
            'message' => 'Todo created successfully',
            'todo' => $todo,
        ]);
    }

    public function show($id)
    {
        $todo = Todo::find($id);
        return response()->json([
            'status' => 'success',
            'todo' => $todo,
        ]);
    }

    public function update(Request $request, $id)
    {
        $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'required|string|max:255',
        ]);

        $todo = Todo::find($id);
        $todo->title = $request->title;
        $todo->description = $request->description;
        $todo->save();

        return response()->json([
            'status' => 'success',
            'message' => 'Todo updated successfully',
            'todo' => $todo,
        ]);
    }

    public function destroy($id)
    {
        $todo = Todo::find($id);
        $todo->delete();

        return response()->json([
            'status' => 'success',
            'message' => 'Todo deleted successfully',
            'todo' => $todo,
        ]);
    }
}

Add API Routes

Open api.php from /routes folder. Add these routes into it.

//...
use App\Http\Controllers\AuthController;
use App\Http\Controllers\TodoController;

//...
Route::controller(AuthController::class)->group(function () {
    Route::post('login', 'login');
    Route::post('register', 'register');
    Route::post('logout', 'logout');
    Route::post('refresh', 'refresh');
});

Route::controller(TodoController::class)->group(function () {
    Route::get('todos', 'index');
    Route::post('todo', 'store');
    Route::get('todo/{id}', 'show');
    Route::put('todo/{id}', 'update');
    Route::delete('todo/{id}', 'destroy');
});

Open terminal and run this artisan command to see all available routes.

Application Testing

Run this command into project terminal to start development server,

php artisan serve

Register API

URL – http://127.0.0.1:8000/api/register

Method – POST

Header

Content-Type:application/json
Accept:application/json

Body

{
   "name": "Sanjay Kumar",
   "email": "sanjay@gmail.com",
   "password": "123456"
}

Login API

URL – http://127.0.0.1:8000/api/login

Method – POST

Header –

Content-Type:application/json
Accept:application/json

Body –

{
   "email": "sanjay@gmail.com",
   "password": "123456"
}

Refresh Token API

URL – http://127.0.0.1:8000/api/refresh

Method – POST

Header –

Authorization:Bearer <token>
Accept:application/json

Logout API

URL – http://127.0.0.1:8000/api/logout

Method – POST

Header –

Authorization:Bearer <token>
Accept:application/json

Create Todo API

URL – http://127.0.0.1:8000/api/todo

Method – POST

Header –

Content-Type:application/json
Authorization:Bearer <token>
Accept:application/json

Body –

{
	"title": "Post 1",
	"description": "Sample Post 1"
}

List Todo API

URL – http://127.0.0.1:8000/api/todos

Method – GET

Header –

Authorization:Bearer <token>
Accept:application/json

Single Todo Detail API

URL – http://127.0.0.1:8000/api/todo/1

Method – GET

Header –

Authorization:Bearer <token>
Accept:application/json

Update Todo API

URL – http://127.0.0.1:8000/api/todo/1

Method – PUT

Header –

Content-Type:application/json
Authorization:Bearer <token>
Accept:application/json

Body –

{
	"title": "Post 2 update",
	"description": "Sample Post 2 content updated"
}

Delete Todo API

URL – http://127.0.0.1:8000/api/todo/1

Method – DELETE

Header –

Authorization:Bearer <token>
Accept:application/json

We hope this article helped you to learn about Laravel 9 REST API Development Using JWT Authentication in a very detailed way.

If you liked this article, then please subscribe to our YouTube Channel for PHP & it’s framework, WordPress, Node Js video tutorials. You can also find us on Twitter and Facebook.