Token-Based Authentication with React and Laravel RESTful API

Authentication and Authorization remain important elements of every software. Most web applications you encounter utilize a cookie-based form of AuthZ and AuthN, where upon signing in, the user is given a cookie with a peculiar identification that links them to a session storage residing on the server. This cookie is submitted with each user request and the server coordinates access to its resources based on the ID and access level of the user initiating the request.

A Token is a meaningless chunk of data which when combined with the right tokenization system becomes an invaluable application security component. With token based Authentication, each request for protected resources to the server is sent alongside a signed token initially received at authentication point, upon which the server verifies its legibility and authenticity, determining whether or not to grant said request.

Most Single Page Applications(SPAs) built with React and other javascript frameworks make use of token based AuthZ as many of them are backed by a REST API — an application programming interface that uses HTTP request to perform GET, POST, PUT and DELETE operations on data.

JSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS). JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA.


Lets get our hands dirty; We will start by building the Laravel API that will serve as a source of data to our React SPA. We will create a Laravel project with a registration, login and users list endpoints, after which a React App that connects to these endpoints will be built.

Creating the Laravel API

STEP 1: create a fresh laravel project by typing this into your terminal that has composer already installed:

composer create-project --prefer-dist laravel/laravel my-project

STEP 2: navigate to the my-project folder using “cd my-project” where we will Install tymon/jwt-auth package in our laravel application:

composer require tymon/jwt-auth

STEP 3: Lets navigate to our config/app.php file and specify the service provider and aliases:

STEP 4: Now we will publish the configuration file using the following command:

php artisan vendor:publish

This generates a config/jwt.php file similar to this but well commented:

STEP 5: We will generate a secret key by running the following command

Laravel 5.4 or earlier:

php artisan jwt:generate

Laravel 5.5 or later:

php artisan jwt:secret

Now if you run either of the above command and you get an error of this sort, which is peculiar to laravel 5.5 and later versions:

“Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist”

You may need to install the dev version of the package with the following command:

composer require tymon/jwt-auth:dev-develop --prefer-source

Now refer to our earlier config/app.php file where we registered the service provider, uncomment

Tymon\JWTAuth\Providers\LaravelServiceProvider::class

for

Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class

Then regenerate the jwt key by rerunning the following command:

php artisan jwt:secret

STEP 6: We need to create a middleware “jwtMiddleware.php” for our JSON Web Token that will validate tokens accompanying requests to the server:

The jwtMiddleware attempts to validate the authenticity of the token, decrypting its content which purportedly carries information about the user requesting a resource or performing an action. It returns an error if the token is invalid or has expired, otherwise the user is allowed access to the system.

STEP 7: We register the jwtMiddleware in our app/Http/kernel.php file:

STEP 8: Next, we create a UserController that registers and logs users in. Upon each login, the controller generates and signs a unique token that’s sent back to the user:

STEP 9: Register API routes in the routes/api.php file. In Laravel, API routes and web routes are registered in separate files to avoid mixing them all up.

We need to create a middleware that appends a Access-Control-Allow-Origin header to all responses from the server. This way the client’s browser would not raise a ‘No Access-Control-Allow-Origin header’ error when resources are requested from servers other the host server.

For instance, we get the above error when we try to access resources from a http://localhost:8000/api/user/login endpoint on a React app that resides at http://localhost:3000. This is so because no Access-Control-Allow-Origin header accompanied responses from http://localhost:8000, the browser will therefore raise an error, denying the app access to the response received from the server.

STEP 10: Create a API.php middleware that appends Access-Control-Allow-Origin header to all outgoing server responses.

We will register the App/Http/Middleware/API.php middleware in the App/Http/Kernel.php file:

Note: If you get any of these errors:

  • Class Tymon\JWTAuth\Providers\JWT\NamshiAdapter does not exist
  • Class Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter does not exist
  • Class Tymon\JWTAuth\Providers\Storage\IlluminateCacheAdapter does not exist

Make the following corrections in your Config/jwt.php file:

// 'jwt' => 'Tymon\JWTAuth\Providers\JWT\NamshiAdapter',
'jwt' => 'Tymon\JWTAuth\Providers\JWT\Namshi',
// 'auth' => 'Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter',
'auth' => 'Tymon\JWTAuth\Providers\Auth\Illuminate',

// 'storage' => 'Tymon\JWTAuth\Providers\Storage\IlluminateCacheAdapter',
'storage' => 'Tymon\JWTAuth\Providers\Storage\Illuminate',

STEP 11: Update User Model:

Firstly you need to implement the Tymon\JWTAuth\Contracts\JWTSubject contract on your User model, which requires that you implement the 2 methods getJWTIdentifier() and getJWTCustomClaims().

This will be the final form of our User model:

We now have our endpoints in place waiting to serve data to our React app. We will create a react application that provides registration, login and homepage functionality.


Creating The React App

We will use the create-react-app command to create a fresh react app with basic dependencies installed

STEP 1: Create fresh react app with create-react-app command

npx create-react-app my-project-react
cd my-project-react
npm start
Note: npx comes with npm 5.2+ and higher.

The newly created directory should be looking like this, excluding Home.js, Login.js and Register.js components that will added later.

my-project-react
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ └── favicon.ico
│ └── index.html
│ └── manifest.json
└── src
└── App.css
└── Home.js
└── Login.js
└── Register.js
└── App.js
└── App.test.js
└── index.css
└── index.js
└── logo.svg
└── registerServiceWorker.js

We will add 3 more dependencies to our react app: “react-router-dom”, “axios”, and “jquery” by running this command:

npm install react-router-dom && npm install jquery && npm install axios

Axios will be used to make a promise based HTTP or network request like Login, Register and fetching list of users from the server

React Router is a collection of navigational components that compose declaratively with your application. It will help us navigate through pages that will be rendered by there respective components.

Note: if you encounter any errors with any of the module, run npm install again

STEP 2: Initialize the App Component by setting the state in the constructor:

this.state = {
   isLoggedIn: false,
   user: {}
};

STEP 3: Create a loginUser function in the App Component src/index.js. This function will make an HTTP POST request with axios to the Laravel API user login endpoint. The Login.js component will call _loginUser() — A parent function that is passed as props to it with, which takes the user login credential as argument.

STEP 4: Create a registerUser function in the App component in src/index.js. This function will make an HTTP POST request with axios to the Laravel API user registration endpoint. The Register.js component will call _registerUser() — A parent function that is passed as props to it with, which takes the user inputs as argument.

On successful login or Registration, the server sends a token along with the logged in user’s details as response. This token is to accompany all further requests to the server (e.g fetching a list of all registered users by the Home component) as it will be used to identify and validate the user.

STEP 5: Create a logoutUser function in the App component in src/index.js file. It will set the application state to the default state, which will have the isLoggedIn attribute set to false. It then saves the state to the local storage after which the app is re-rendered by calling the this.setState function with the new state as argument.

When the App component mounts, we want it to fetch the last known state of the app which has been saved to local storage — if any — and then update itself with this fetched state:

The final look of the App component can be seen on the embedded codesandbox project.

STEP 6: Create the Register component. The register component is a stateless one that takes the _registerUser function as props from the parent component (App component).

STEP 7: Create the Login component. The login component is also a stateless one that takes the _loginUser function as props from the parent component (App component).

STEP 8: Create the Home component. The Home component after mounting, using axios, fetches a list of all users registered on the server(so you can register multiple users to populate the list) through the Laravel API. The API call is accompanied with the user token initially gotten from the server on Login/Registration.

The users list is a protected resource which is only available to authenticated and authorized users. The Laravel API evaluates the token passed along with the request. This request is then only granted on successful validation of the token, else the server returns an “Unauthorized” response.

Conclusion:

In this article, we’ve learnt how to create a laravel RESTful API that performs token-based authentications and we’ve also created a React application that fetches resources from this Laravel API by providing stored tokens received at authentication point.

If you are looking to scale your Laravel Application here is a guide i recently published:

Did you find this tutorial useful ? Then hit that clap button and follow me to get more articles and tutorial on your feed.