,

Complete Tutorial: Authentication in React using JWTs, Access Tokens, and Refresh Tokens

Posted by


Introduction:
Authentication is a crucial aspect of any web application, as it helps verify the identity of users and control access to protected resources. In this tutorial, we will explore how to implement authentication in a React application using JSON Web Tokens (JWTs), access tokens, and refresh tokens.

JSON Web Tokens (JWTs) are a compact, URL-safe way of representing claims to be transferred between two parties. JWTs can be signed using a secret or a public/private key pair, and can be used to securely transmit information between parties.

Access tokens are short-lived tokens that are used to access protected resources, while refresh tokens are long-lived tokens that can be used to obtain new access tokens once they expire.

Prerequisites:
To follow this tutorial, you should have a basic understanding of React, as well as some knowledge of JWTs and how they can be used for authentication.

Step 1: Setting up the React application
First, let’s create a new React application using Create React App. Open your terminal and run the following command:

npx create-react-app authentication-app

Once the application has been created, navigate to the project directory and start the development server by running:

cd authentication-app
npm start

Step 2: Implementing the authentication flow
Now that we have our React application set up, let’s implement the authentication flow. We will create a simple login form that will take the user’s credentials and authenticate them using a backend service.

First, let’s create a new component for our login form. In the src folder, create a new file called LoginForm.js and add the following code:

import React, { useState } from 'react';

const LoginForm = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();

    // Call a backend service to authenticate the user

    setUsername('');
    setPassword('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text"
        placeholder="Username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input 
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
};

export default LoginForm;

In this code, we have created a simple login form that takes the user’s username and password. When the form is submitted, we will call a backend service to authenticate the user.

Step 3: Authenticating the user
To authenticate the user, we will use JWTs to generate an access token and a refresh token. We will also create a backend service to handle the authentication process.

First, let’s install the necessary dependencies. In the terminal, run the following command:

npm install axios jsonwebtoken

Next, let’s create a new file called authService.js in the src folder and add the following code:

import axios from 'axios';
import jwt from 'jsonwebtoken';

const authService = {
  login: async (username, password) => {
    try {
      const response = await axios.post('http://localhost:5000/login', { username, password });
      const { accessToken, refreshToken } = response.data;
      localStorage.setItem('accessToken', accessToken);
      localStorage.setItem('refreshToken', refreshToken);
      return true;
    } catch (error) {
      console.error('Authentication failed');
      return false;
    }
  },

  logout: () => {
    localStorage.removeItem('accessToken');
    localStorage.removeItem('refreshToken');
  },

  refreshToken: async () => {
    const refreshToken = localStorage.getItem('refreshToken');

    if (!refreshToken) {
      console.error('Refresh token not found');
      return;
    }

    try {
      const response = await axios.post('http://localhost:5000/refreshToken', { refreshToken });
      const accessToken = response.data.accessToken;
      localStorage.setItem('accessToken', accessToken);
    } catch (error) {
      console.error('Failed to refresh access token.');
    }
  },

  getAccessToken: () => {
    return localStorage.getItem('accessToken');
  },

  isAuthenticated: () => {
    const accessToken = localStorage.getItem('accessToken');
    return accessToken ? true : false;
  }
};

export default authService;

In this code, we have created a service that handles authentication logic. The login method sends a POST request to the backend login endpoint with the user’s credentials and stores the access and refresh tokens in local storage.

The refreshToken method sends a POST request to the refreshToken endpoint with the refresh token to obtain a new access token.

Step 4: Connecting the login form to the authentication service
Now that we have implemented the authentication logic, let’s connect the login form to the authentication service. Update the LoginForm.js file as follows:

import React, { useState } from 'react';

import authService from './authService';

const LoginForm = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();

    const success = await authService.login(username, password);

    if (success) {
      console.log('Authentication successful');
    } else {
      console.log('Authentication failed');
    }

    setUsername('');
    setPassword('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text"
        placeholder="Username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input 
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button type="submit">Login</button>
    </form>
  );
};

export default LoginForm;

In this code, we have imported authService and called the login method when the form is submitted. If the authentication is successful, we log a success message, otherwise we log a failure message.

Step 5: Protecting routes
Now that we have implemented authentication, let’s protect some routes in our application. We will create a private route component that only allows authenticated users to access the protected route.

Create a new file called PrivateRoute.js in the src folder and add the following code:

import React from 'react';
import { Route, Redirect } from 'react-router-dom';

import authService from './authService';

const PrivateRoute = ({ component: Component, ...rest }) => {
  return (
    <Route
      {...rest}
      render={(props) =>
        authService.isAuthenticated() ? <Component {...props} /> : <Redirect to='/login' />
      }
    />
  );
};

export default PrivateRoute;

In this code, we have created a PrivateRoute component that checks if the user is authenticated using the isAuthenticated method from the authService. If the user is authenticated, the component is rendered, otherwise the user is redirected to the login page.

Step 6: Summary
In this tutorial, we have explored how to implement authentication in a React application using JSON Web Tokens (JWTs), access tokens, and refresh tokens. We have created a login form, implemented the authentication flow, protected routes, and handled token expiration.

By following this tutorial, you should now have a solid understanding of how to implement authentication in your React applications using JWTs. Remember to always follow best practices for securing and managing tokens to ensure the security of your application.

0 0 votes
Article Rating

Leave a Reply

40 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
@cosdensolutions
2 days ago

Hope you enjoyed the video! 😁 I also have a really cool and unique course that will teach you way more than this video. You'll learn how to build an actual complex project with React. It's called "Project React" and you can find it at https://cosden.solutions/project-react. Also, I have a free weekly newsletter called "Import React" with tutorials, news, and cool stuff about React! You can sign up at https://cosden.solutions/newsletter?s=ytc

@algnadjib
2 days ago

why calling: await api.get("/api/refereshToken"); if expired throws an error??
it should return 403 which is not an exception!

@lcpriya
2 days ago

Awesome videos, thank you. Can you please post a video on user Authentication in React using RTK query

@AlgoKemal
2 days ago

Even if an attacker gains access to access token, they can’t do much with it because they don’t know the secret used to sign the JWT. The secret is stored server-side and remains hidden, preventing them from forging or tampering with the token

@saeidghorbani-s6b
2 days ago

very helpful. thanks

@gastonmartinezcastro3781
2 days ago

If the token is null, do you not already know the call to refreshToken will fail? If it was undefined because of a refresh then the useEffect would hit /api/me to get it, but null only tells you that the user is logged out

@LucasHenrique-lv8mc
2 days ago

Fail on multiples requests if you are on login page for example.

Cause loops if you are not authenticated

@MelissaWilliams-o4y
2 days ago

Meta Neck

@RajuSharma-ms8jf
2 days ago

im little confuse about mine code , if mine access token is null and i make a call with /api/me to generate new access Token , then will i get new access token ,
if yes then everyone gonna have this accessToken and use even to generate tokens

one more confusion , if i gonna store access token in memory then i dont thinks its permanently stores on state , when ever server start stops its gonna clear , even if its store will it gonna be different for all user or accessing same refresh token every user using this web app

i'm new to it , im so confuse , please help me

@iamnot664
2 days ago

Useful but not very useful at the same time

@shirleybargeman4484
2 days ago

Martin Elizabeth Martinez Ruth Hernandez Edward

@langqin
2 days ago

Hi, what if I had a different domain for backend?

@PriyankBolia
2 days ago

What is API variable, is there a github repo for this.

@Jonatandb
2 days ago

Thanks! very useful, could you please share the backend refreshtoken source code? 🙌🏻

@furycorp
2 days ago

I clicked through different parts and it seems like this video contains inaccurate information. Viewers should beware. e.g. "This refresh token … the server is never going to send it to the front end" is completely wrong if its stored as an HttpOnly cookie. Those are generally always sent to the client… This is a very authoritative looking video but then skipping through parts its like "does this guy even know what a cookie is"? It is crucial HttpOnly cookies are configured correctly and only used with HTTPS. HttpOnly means exactly that: as a convention the browser will not allow *JavaScript* to read or set this type of cookie. A zero JS cookie is therefore an *HTTP only* cookie. This prevents key attack vectors — for example malicious JS injected into a blog comment by an attacker on a site that makes a few security gaffes, and that JS then reads JWT's or other secrets and sends them back to the attacker. Viewers should also understand the SameSite attribute. Read the OWASP guidelines.

@FUNKYSTUFFM8
2 days ago

next 14 server auth please!! so good this one

@Aliena92
2 days ago

WOW, amazing! Thank you so much!

@gilbertsalomon9127
2 days ago

Abshire Ferry

@DelmerSin-f7l
2 days ago

Hilpert Lights

@artemvolsh387
2 days ago

Instant subscription, clear, on-point, full of useful theory and practical example. 👏

40
0
Would love your thoughts, please comment.x
()
x