Skip to main content

Authentication & Authorization in ReactJS


The more our personal and business data flows online, the more concerned people are about internet security. Users desire application integration without having to provide user login information all the time. They also desire security without being aware that it is present. 


Authentication is concerned with identifying an entity (i.e user, server, or device). A web application may request a username and password when identifying a user. If a cloud service wants to locate a server, it may request the IP address. Finally, devices may be recognized by their unique MAC addresses. 

Similarly, authorization permits one party to get access to another (or resource). A home key is a good example of how permission varies from authentication. A door lock is unconcerned about who is using the key to enter the residence. It merely recognizes that persons in possession of the home key have permission to enter. In this article, we’ll be discussing how to curate a ReactJS application while implementing  API authorization and authentication. 

Methods of Putting API Authorization & Authentication in ReactJS

ReactJS is a Javascript front-end framework for creating user interfaces. Furthermore, the framework is frequently used to create SPAs (single-page applications). Single-page apps are loaded into the browser. This indicates that none of the information in the SPA is secure. 

As a result, React apps that use the SPA paradigm cannot store API keys on the front end for permitted access. This limits the application's ability to authorize itself for third-party API requests. This, however, does not prevent it from authenticating. 

Creating a React App that utilizes Authentication and API Authorization

In this article, we will show the distinctions between authentication and permission in a React project. We can do this by emulating the authentication principles of a React app and building an OAuth application via Github that allows our application to retrieve Github user data over the Github API. 

The Next.js framework will be used to construct the application. We’re choosing Next.js because it offers the following features: 

●    A simple page-based routing scheme (with support for dynamic routes). 
●    On a per-page basis, pre-rendering, static generation (SSG), and server-side rendering (SSR) are available.
●    Splitting code automatically for quicker page loading. 
●    Routing on the client-side with efficient prefetching. 
●    CSS and Sass support is built-in, as is support for any CSS-in-JS library.
●    API routes are supported in the development environment with Fast Refresh to construct API endpoints with Serverless Functions.
●    It is completely extensible.

The most essential aspect of Next.js is that it "generates HTML for each page in advance, rather than having it all done by client-side JavaScript." Pre-rendering can improve speed and SEO.” Furthermore, Next.js allows us to construct API routes within the folder of our application project. 

This is ideal for backend programming or code that deals with sensitive data. Next.js comes with a slew of capabilities out of the box and is suggested by ReactJS.org as one of the technologies to utilize when developing a React project. We've got a lot to cover in this application, so let's get started!

Requirements for curating a ReactJS app with authentication and API Authorization. 

●    NodeJS is already installed locally (10.13 or later). 
●    Understanding of how to utilize a command-line program. 
●    Download Git for Windows and use the Git BASH program that comes with it if you're on Windows.
●    Knowledge of NodeJS and React is required.
●    Code editor with internet connectivity (Sublime, VSCode). 
●    Account on Github. 

Create the Next.js project.

Navigate to the location where you want to create the app in a terminal program (BASH, Git BASH, Terminal, Powershell, etc.). The command cd may be used at the terminal to do this. Run the command npx create-next-app in the terminal. When prompted, give the project a name (for example, react-authentication).

import Head from 'next/head'
import styles from '../styles/Home.module.css'
export default function Account({ query }) {
 React.useEffect(() => {
  // Call the Github API route to fetch user data
 }, [])
 return (
   <div className={styles.container}>
     <Head>
       <title>Account</title>
       <link rel="icon" href="/favicon.ico" />
     </Head>
     {/* Add logout button */}
     <main className={styles.main}>
       <h1>Authenticated Account Page</h1>
       <section className={styles.data}>
             <h2>Basic User Information</h2>
             <small>Since we know it's you.. here's your information!</small>
             {/* Display user information */}
       </section>
       <section className={styles.data}>
         <h2>Github OAuth</h2>
         <small>Authorize this application to acces your Github information.</small>
         {/* Add Github component */}
       </section>
     </main>
     <footer className={styles.footer}>
       <a
         href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
         target="_blank"
         rel="noopener noreferrer"
       >
         Powered by{' '}
         <img src="/vercel.svg" alt="Vercel Logo" className={styles.logo} />
       </a>
     </footer>
   </div>
 )
}


Individual pages are produced from the Javascript scripts in the pages directory. In this directory, create a file called account.js and paste the following code into it. In the preceding file, we generated a page with the same styles and structure as index.js. Let's fire up the development server and examine what we've got so far.

Run npm run dev at the root of your project directory (react-authentication). This will launch a development server at http://localhost:3000. In your browser, navigate to the webpage. You should see the Next.js project's default beginning page. Change the URL in the browser to http://localhost:3000/account. The page that we generated in pages should now be visible.

API Routes are Stored Under the Pages Directory 

The names of the API routes that our client application may call at /API/[route name] are stored in the API folder under the pages directory. The sample API route provided by the starting project is http://localhost:3000/api/hello. If you go to that URL, you'll see:

'name': "John Doe"

If we look at the pages/API/hello file, we can see that this is precisely what this method should return if an HTTP request is received.

Delete the file pages/API/hello and replace them with four new files in the pages/API folder:

auth.js
logout.js
user.js
github.js

Insert the following code into each of the new files.

const allowedMethods = []
export default (req, res) => {
   res.setHeader('Allow', allowedMethods)
   if (!allowedMethods.includes(req.method)) {
       return res.status(405).end()
   }
   return res.status(200).end()


CSS files in the styles directory might be global or modular. In the Home.module.css file, we may define CSS classes and then import that file as an object into a component file. Then, on the imported styles object, we can access the defined class names.

The globals.css file is used to style all elements such as li>, body>, and so forth.

Insert the following styles into styles/Home.module.css. Do not remove any of the existing styles from the file.

....
.input {
 display: block;
 margin: 5px;
 border-radius: 5px;
 border: 1px solid #CCC;
 font-size: 1.2em;
 line-height: 1.7em;
 -webkit-border-radius: 5px;
 -moz-border-radius: 5px;
 -ms-border-radius: 5px;
 -o-border-radius: 5px;
}
.button {
 font-size: 1.2em;
 color: white;
 border: none;
 padding: .4rem .7rem;
 background: #0070f3;
 border-radius: 2px;
 margin-right: auto;
 -webkit-border-radius: 2px;
 -moz-border-radius: 2px;
 -ms-border-radius: 2px;
 -o-border-radius: 2px;
}
.formGroup {
 margin: 10px;
}
.data {
 border: 1px solid #CCC;
 margin: 1rem auto;
 padding: 1rem;
 border-radius: 5px;
 -webkit-border-radius: 5px;
 -moz-border-radius: 5px;
 -ms-border-radius: 5px;
 -o-border-radius: 5px;
}
.github {
 margin: 1rem auto;
}
.github > a {
 color: blue;
}
....


You now have an understanding of how a Next.js project should be structured. Taking this into consideration,  we will now proceed with adding a login component, user data, and user authentication as well.

Implement User Authentication

To begin, add a form to the index.js file that will take a user's email and password. Replace all of the code within the main> HTML tag with the following:
...
      <h1 className={styles.title}>
         React API Authorization
       </h1>
       <div className={styles.grid}>
         <div className={styles.card}>
           <h3>Login &rarr;</h3>
           <form>
             <div className={styles.formGroup}>
               <label htmlFor="email">Email</label>
               <input
                 onChange={(e) => setUsername(e.target.value)}
                 className={styles.input}
                 autoComplete='on'
                 type="email"
                 id="email"
                 name="email" />
             </div>
             <div className={styles.formGroup}>
               <label htmlFor="password">Password</label>
               <input
                 onChange={(e) => setPassword(e.target.value)}
                 className={styles.input}
                 type="password"
                 id="password"
                 name="password" />
             </div>
             <button onClick={(e) => login(e)} className={styles.button}>Login</button>
           </form>
           <p>
             Authenticate as a user via the mock server
             </p>
         </div>
       </div>

The preceding code generates a form that accepts two React state variables (set up using React Hooks). The submit button causes a functioning login to be executed. Next, we must define this function as well as our state variables.

Add; above the return statement in index.js.

...
 const router = useRouter();
 let [username, setUsername] = React.useState('')
 let [password, setPassword] = React.useState('')
 const login = async (e) => {
   e.preventDefault()
   try {
     await api.post('/api/auth', { username, password })
     router.push('/account')
   } catch (e) {
     setPassword('')
     console.log(e)
   }
 }
...


In index.js, add; after the return statement.

import React from 'react'
import api from '../api'
import { useRouter } from 'next/router'
...


Because we haven't yet built the API module, saving the file will result in an error. But, before we do so, let's have a look at the component code. 

Next's use router hook was imported. This allows us to manage the user's navigation while also utilizing Next's routing functionalities. Then we supplied our React state hooks for username and password. 

Finally, we developed an asynchronous function that invokes the /API/auth API route (sending the user credentials). If the request to that route is successful, the user is routed to the /account page (through the router). If it fails, the password is cleared and an error message is logged to the console.

Saving the file will result in an error because we haven't yet constructed the API module. But first, let's have a look at the component code. The use router hook from Next was imported. This allows us to manage the user's navigation while simultaneously making use of Next's routing capabilities. Then we supplied our React state hooks for username and password.

Make an API File

An Axios instance is contained in the API module, which is a distinct file. Create the api.js file in the project's root directory. In that file, paste the following code:

import axios from 'axios'
const api = axios.create({
   baseURL: 'http://localhost:3000',
   headers: {
       'Accept': 'application/json',
       'Content-Type': 'application/json'
   }
});

export default API;

Save the document once done. We're almost done with the auth.js file, but we need to use npm to import Axios into our project. Return to your command prompt and type npm install Axios in the project folder. It's possible that the development server will need to be restarted. 

After you have saved all of the new file changes, your home page should appear like this. We will make a file to simulate a database with user data. Create the file data.js in the project root (same directory as the api.js file) and add the following code.

export default [
   {
       id: 1,
       name: 'Jarrett',
       email: 'jarrett@app.org',
       password: 'react-authentication123',
   }
]


Of course, you can change the user object's contents or manually add more user objects.

When a user presses the Login button, the login function is called, which calls the /API/auth route. This path must include the following features:

●    Verify that the request method is permitted.
●    Check to see if the user already exists.
●    Verify that the password is accurate.
●    Set an authorization cookie and return the HTTP status code 200 if the credentials are found.

Authentication Through Cookies

Add 'POST' to the allowed Methods array in /api/auth. Import data.js with the line import data from '../../data' at the top of the code. Then, from the request, extract the credentials and look for a user. Underneath the if statement, add the following code to check for authorized HTTP methods.
...
 const {
   body
 } = req
  
 const {
   username,
   password
 } = body
// Validate credentials middleware
 const user = data.find(user => user.email === username)
...


Insert the following IF statements to verify whether the user exists and if the password is correct. In case either fails, we return a 404 Not Found status code.

...
 if (!user) {
   return res.status(404).end()
 }
  if (!user.password !== 'password') {
   return res.status(404).end()
 }
...


Finally, we set a cookie on the res object if the credentials match. The cookie module is a simple way to serialize cookies. Run npm install a cookie in the project root to add this module to the project. Add this code underneath the if block containing the password check and import cookie at the top of the file.

...
 res.setHeader('Set-Cookie', cookie.serialize('authorization', user.name, {
   httpOnly: true, // Javascript can't access value
   secure: process.env.NODE_ENV === 'development' ? false : true, // Only use HTTPS
   sameSite: 'strict', // Only send cookie to this site
   maxAge: 600, // In seconds
   path: '/' // Should be set to avoid problems later
 }));
...


This cookie is only delivered to our website and cannot be accessed (hijacked) by malicious Javascript. It has an expiration date and may be used only with HTTPS. The value of this cookie is usually a session ID that is stored in the database or controlled by a session library/database. 

Alternatively, a JWT can be used. Set important information as the cookie value if it is not encrypted. Regardless, we will make an exception for this example and set the user's name as the value. This makes it easier to locate the user in later functions. You may now sign into the application using the credentials saved in data.js. You will be routed to the account page if the sign-in was successful. 

Making a Logout Function

Let's add a logout mechanism to the account page that sets a new cookie and redirects the user back to the home page after the authorization cookie expires. Import the cookie module at the top of the /API/logout file. a cookie from the 'cookie' folder. Then, add 'GET' as one of the authorized methods. 

Once done, before the return statement, insert this set cookie code.

...
 res.setHeader('Set-Cookie', cookie.serialize('authorization', '', {
   httpOnly: true,
   secure: process.env.NODE_ENV === 'development' ? false : true,
   sameSite: 'strict',
   maxAge: new Date(),
   path: '/'
 }));
...


Now, add the logout function to pages/account,

..
 const logout = () => {
   api.get('/api/logout').then(() => {
     router.push('/')
   })
 }
...


below the Head component, add a button that calls the method.
...
     <button className={styles.button} style={{ background: 'red', margin: 'none' }} onClick={() => logout()}>&larr; Logout</button>
...

Similarly, below the Head component, add a button that executes the function.

...
 const router = useRouter();

Bottom Line 

In this article, not only do we see how to implement authentication and authorization in ReactJS, but we also understand the various requirements needed for curating a ReactJS application along with API Authorization. 

We have also shed some light on how to implement user authentication and how you can curate an API file accordingly. Since knowing authentication through cookies and a logout function is crucial, we have discussed these as well.


Source: https://www.zenesys.com/blog/authentication-and-authorization-in-reactjs


Comments

Popular posts from this blog

Creating S3 Buckets using Terraform

In this blog post, we will learn to create S3 Buckets using Terraform - Infrastructure as Code. Table of Contents ● What is Terraform? ● What is S3? ● Installation of Terraform ● Installation of AWS CLI ● Configuring AWS CLI ● Create Working directory for Terraform ● Understanding Terraform files ● Creating Single S3 Bucket ● Creating multiple S3 Buckets PreRequisites ● Installation of Terraform ● Installation of AWS CLI ● IAM user with Programmatic access  What is Terraform? ● Terraform is a tool to create , delete and modify the resources. ● Supported clouds such as AWS, Azure and GCP , IBM cloud etc. What is S3? S3 stands for Simple Storage Service. Amazon S3 has a simple web services interface that you can use to store and retrieve any amount of data, at any time, from anywhere on the web.  Installing Terraform 1. Using binary package (.zip) 2. Compiling from source Install Terraform From the link provided above, Download the suitable packag...

10 Best Python Libraries For Machine Learning

With the increase in the markets for smart products, auto-pilot cars and other smart products, the ML industry is on a rise. Machine Learning is also one of the most prominent tools of cost-cutting in almost every sector of industry nowadays. ML libraries are available in many programming languages, but python being the most user-friendly and easy to manage language, and having a large developer community, is best suited for machine learning purposes and that's why many ML libraries are being written in Python. Also, the python works seamlessly with C and C++ and so, the already written libraries in C/C++ can be easily extended to Python. In this tutorial, we will be discussing the most useful and best machine-learning libraries in Python programming language. 1. TensorFlow : Website: https://www.tensorflow.org/ GitHub Repository: https://github.com/tensorflow/tensorflow Developed By: Google Brain Team Primary Purpose: Deep Neural Networks TensorFlow is a library developed by the G...

Determining ROI for Your RPA Project

  Nowadays, every business needs to reach seamless Business Process Automation and offer the best possible customer experience. In 2021, the old-school way of going by your business won’t cut it. The introduction of RPA services (Robotic Process Automation) is crucial in simplifying your business processes. Its benefits are difficult to overstate.  Since it is non-disruptive, the implementation of RPA is not as complex as it appears to be. However, calculating the Return On Investment for RPA automation isn’t straightforward. You have to consider things that you won’t even realize are countable. Calculating the costs and gains for RPA services can put you in a pickle at times. But fret not.  This article will shed light on everything you need to know and consider before calculating the ROI for your RPA project.  How to Calculate ROI for your RPA Project?  1. Determine Your Automation Goals Before you start automating business processes with RPA services, you nee...