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.
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
why calling: await api.get("/api/refereshToken"); if expired throws an error??
it should return 403 which is not an exception!
Awesome videos, thank you. Can you please post a video on user Authentication in React using RTK query
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
very helpful. thanks
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
Fail on multiples requests if you are on login page for example.
Cause loops if you are not authenticated
Meta Neck
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
Useful but not very useful at the same time
Martin Elizabeth Martinez Ruth Hernandez Edward
Hi, what if I had a different domain for backend?
What is API variable, is there a github repo for this.
Thanks! very useful, could you please share the backend refreshtoken source code? 🙌🏻
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.
next 14 server auth please!! so good this one
WOW, amazing! Thank you so much!
Abshire Ferry
Hilpert Lights
Instant subscription, clear, on-point, full of useful theory and practical example. 👏