From zero to confident API dev using JWT and Laravel

(Part-2: Implementation of JWT along with Laravel)

Hi there, welcome back. In part 1 we talked about the basic concept of API and JWT. If you haven’t read that give that a shot as this is a sequence of that part and this part focus on the hands-on implementation of API rather than discussing concepts.

Ok, so we know what is API, JWT, and what stateless authentication is. Let’s move on to the next step, making API. And as we discussed in the previous part that you need to have knowledge of the composer. We gonna install/manage our dependencies using that.

So the very first step is to add the tymon/jwt-auth package to your project.

You can additionally add a version while installing but that is optional. If you don’t provide that it will be downloaded from the latest stable version.

Next, you need to publish the package’s config file. It will let you make more changes according to your need. This command will add a jwt.php file in the config folder. This file returns an array with the config options that are used to handle and manage tokens.

In order to make a valid token, you will need a secret key which will be retrieved from your .env file from the “JWT_SECRET” key. You can put any random string there or simply fire “php artisan jwt:secret” command to do it for you.

It will add a JWT_SECRET key to your .env file with a long random string value. In case you had it there before, it will override that.

The next step is to change the driver for API authentication. Go to your laravel project followed by the config folder. You will find an auth.php file. This file basically holds the configuration for authenticating users. Here you can declare various providers and drivers. In a fresh laravel project, the default driver is the ‘web’. You can change it anytime. In case your application only deals with API you can set the default driver from web to api.

But we are not done yet with the configuration. As you see we have changed the default guard, we haven’t change the driver yet. If you scroll down the auth.php file from top to bottom you will find an array key named ‘guards’. This key holds the driver settings for available/declared guards. Now, there you will find the index ‘api’ and under that the driver. By default the driver is token. But as we are using JWT(token) so we need to change that too.

Now hit the

php artisan config:cache

command to re-cache the changes. By hitting that command we are done with the configuration. Next, we have to implement the ‘Tymon\JWTAuth\Contracts\JWTSubject’ contract on our User model.

So why the User model why not other models?

It’s because in the configuration file (config/auth.php) array the provider for authenticating users is set to the User model.

In case you want to use a different table/model to authenticate your users you have to change the provider's section and under that the model part. Coming back to the point. We have implemented the JWTSubject contract on our User model. Now, this contract requires implementing two methods.

  1. getJWTIdentifier()
  2. getJWTCustomClaims()

getJWTIdentifier()

This method basically returns a value that will be sent to your payload of the JWT token(as a value of ‘sub’ key). In most cases, you will return the id/primary key of the model. But you can return any other value matching your model key.

getJWTCustomClaims()

This method returns an array. An array of custom data that you want to merge with your payload of the JWT token. It’s an optional choice that you might not want to add any custom information. In that case, just return an empty array(which is the default). Note that no secret information should be passed in the payload as it can be extracted.

We are all set with our model. Now we need a controller that will be used to handle our request. Let’s make an auth controller quickly by hitting the command

php artisan make:controller AuthController

At this moment we need to think a little and that is what we want to implement to our AuthController or what kind of request will be handled by it.

We need an endpoint to login and a method to handle that

We need an endpoint to logout and a method to handle that

We need an endpoint to retrieve logged user’s information and a method for that.

We need an endpoint to refresh our token.

Let’s start by creating the route for them first. As those are our API endpoints. We gonna add them to our routes/api.php file.

Route::group([

'middleware' => 'api',
'prefix' => 'auth' // optional

], function ($router) {

Route::post('login', 'AuthController@login');
Route::post('logout', 'AuthController@logout');
Route::post('refresh', 'AuthController@refresh');
Route::post('me', 'AuthController@me');

});

Next, implements the method in our AuthController.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}

/**
* Get a JWT via given credentials.
*
* @return \Illuminate\Http\JsonResponse
*/
public function login()
{
$credentials = request(['email', 'password']);

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

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

/**
* Get the authenticated User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function me()
{
return response()->json(auth()->user());
}

/**
* Log the user out (Invalidate the token).
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth()->logout();

return response()->json(['message' => 'Successfully logged out']);
}

/**
* Refresh a token.
*
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth()->refresh());
}

/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}

A few extra methods right? Don’t worry we will cover them. Let’s start with the constructor method. We know that the constructor method is called every time an instance is created of that class. So here, this method is going to be called whenever we access any method of the class from outside of the class. Another thing we are telling here is that use the auth middleware for the methods declared in the class and use the api guard among the available guards from our configuration. And we don’t want to apply our middleware in the login method as the user is unauthenticated until he logs in. So we are telling that in the except index of the array.

Then in the login method, we are validating the user’s input first and then matching them with our database records. If not matched we are sending an unauthorized message to the user/client. In case the credential does match with our records we are receiving a token which refers to the JWT token. And we are sending it in a formatted way along with the token type and expiration time.

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

This token will be stored on the client-side and will be sent through the header or query parameter to authenticate the user.

Next in me() method, we are simply returning the information of the authenticated user in JSON format. Nothing fancy here.

And in the logout method, we are logging out the user. And behind the scene, we are invalidating the token so that the user can’t use the same token to authenticate after successful logout.

Lastly, in the refresh method, we are doing the same thing as we did for logout. But here instead of forcing the user to log out, we are just invalidating the token and returning a new token to the user which can be used for further requests.

All are set. Now it’s time to test the endpoints and check if our API works according to our plan. There are some awesome API Clients available in the market. You can pick any of them. I am using Postman here.

Let’s hit the login route first.

As you can see a long string(token) passed against the access_token key is your desired JWT token. In which the first part(before the first dot) holds the information about the algorithm(header) and the middle part holds information(payload) and the last part is your encrypted secret key.

Now, this token will be sent as a header or query parameter with every request.

That’s all folks. Now you can build API on your own using Laravel and JWT.

Don’t forget to clap if you liked it and feel free to share it with others.

A software engineer from Bangladesh.