API Authentication with Laravel + JWT

Joshua Etim
Level Up Coding
Published in
5 min readApr 6, 2022

--

Introduction

Authentication is a basic feature of most services on the internet. We want to be able to restrict who has access to what, and to do it in the most convenient and secure way possible. This article seeks to cover authentication in API services using the Laravel PHP framework and JWT. This article assumes you have some experience writing Object-Oriented code in PHP.

API Authentication?

Yes, we will be authenticating our users with a Web Service API, specifically a RESTful API service. This article assumes we want to separate the frontend from the backend services and in this tutorial series, we will build a client to interact with the API we’re building.
If we weren’t using REST API, we would have to use sessions to authenticate the user. This way, the server creates a new session file for the user, and gives it a unique identifier which is sent to the user and saved to the user as a cookie. This is often described as a stateful system.

For our API service (which is stateless), we will be using tokens, which is often issued by the server, and carried by the client during every request. In this system, there is no memory of user activity — every request is taken as the first.
For this application, we will be using JWTs (JSON Web Tokens) as our tokens to be issued and validated by the server. A JWT simply carries encoded JSON data and is often used as authorization tokens in API services. (Read more on JWTs — https://auth0.com/docs/secure/tokens/json-web-tokens)

JWTs vs Sanctum

If you’ve worked with APIs in Laravel before, you must have come across Sanctum or Passport as effective means of authenticating users on your services. Why JWTs then?

I worked with Sanctum for a while before coming across JWTs. One thing I noticed was that the tokens were stored in the database. So for every request, a database query is made to validate the token, and then another to fetch the user information. The overhead that process adds to every request is substantial. Also, you have little or no use for the tokens apart from them being randomly generated strings to query the database against. That takes up space without doing much for you. In another instance, if you login multiple times, you get several tokens added to your database, most of which are useless and waiting to be deleted. A separate article can be written about these limitations and how they can affect you in production.

In contrast, JWT tokens are self-contained, and are mainly the responsibility of the client. Your server simply generates a token and sends to the client without a care of what happens to the tokens. This means you can login multiple times, and this doesn’t affect the server side in any way. Additionally, you get to manipulate the data on the tokens. You could store the user info in the token, removing the need for an additional database query. In a sense, this is the original idea of what access tokens are supposed to be in the context of our application.

Setup and configurations

To get started, we need to install a fresh Laravel application. For this tutorial, we will using Laravel 8 so everyone follows, but keep in mind that Laravel 9 is available and can be used with this tutorial.
To install Laravel 8, use the command below:

composer create-project laravel/laravel:^8.0 jwt-laravelcd jwt-laravel

Next, we install the tymon/jwt-auth package:

composer require tymon/jwt-auth:*

We use the * wildcard because some existing packages might conflict with what the latest version of jwt-auth and we want to install the version we can at least get.

Next, in the providers array in the config/app.php file, add the JWT provider at the end of the array:

// […other providers],
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,

At the end of the aliases array in the same file, add the following values:

‘JWTAuth’ => Tymon\JWTAuth\Facades\JWTAuth::class, 
‘JWTFactory’ => Tymon\JWTAuth\Facades\JWTFactory::class,

The GitHub repository for this project can be seen at: https://github.com/joshuaetim/jwt-laravel-article

Run the command below to publish the config file:

php artisan vendor:publish –provider=”Tymon\JWTAuth\Providers\LaravelServiceProvider”

And this command to generate a secret key:

php artisan jwt:secret

Edit your Models

Before your models can use JWT for authentication, you need to set it up for just that. For our User model, that means implementing the JWTSubject interface from the package we just installed. To successfully implement an interface in PHP, we must implement the functions defined in the interface.

Here’s what our User model will look like:

Next you set up your database and run your migration with the command below:

php artisan migrate

Define routes

Our routes represents the mappings of urls to handler functions. For this step, we will have routes to handle welcome page, registration, login, dashboard, and fetch user.
Here’s what out routes/api.php looks like:

The dashboard route is protected by the ‘jwt.verify’ middleware, which we will create later.

Define controllers

We create a new controller named AuthController to handle our authentication needs:

php artisan make:controller AuthController

The contents of AuthController is given below:

In the file, we created functions to format our success and error responses to reduce duplication. Then we set up methods for registration, login and fetching the current user.

Define middleware

We will be using a middleware to protected certain routes such as the dashboard route defined earlier, and the middleware will be called before the request is handled.

To create the middleware run the following command:

php artisan make:middleware JWTMiddleware

The contents of JWTMiddleware is shown below. It basically tries to get the current authenticated user from the request headers. If the user isn’t found or the there’s an issue with the token, an error response is returned.

To register this middleware, go to App/Http/Kernel.php and in the $routeMiddleware array, add this value at the end:

 ‘jwt.verify’ => \App\Http\Middleware\JWTMiddleware::class,

If you noticed, we never touched the original auth() service or middleware provided by Laravel. This is convenient for us for when we might want extend or implement the main authentication service. If you want to use the main auth() service, simply change the api guard provider to ‘jwt’ in config/auth.php. More information on that can be found here: https://jwt-auth.readthedocs.io/en/develop/quick-start/

Coming soon

In the next part, we will

  • implement custom helper functions to help us better in our authentication process,
  • allow users to logout of the service

Stay tuned, and let me know if you have any feedback for me. Be sure to clap so others see the story too.

--

--