Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for How to manage user authentication With React JS
Makanju Oluwafemi
Makanju Oluwafemi

Posted on • Edited on

     

How to manage user authentication With React JS

Before getting started, I want you to also check this article on how charge API work in fintech. Please checkhere

The management of user access stands as a pivotal aspect of web application development. In this comprehensive guide, you will learn and understand the intricate workings of authorization and authentication in React.js. This article caters to readers possessing a fundamental understanding of React, providing them with invaluable insights. Moreover, seasoned front-end engineers will discover a detailed workflow for session management within the realm of this guide.

To get started, you will need to set up aReact project by running the command

npx create-react-app your-project-name
Enter fullscreen modeExit fullscreen mode

Also, you can run

npminstallreact-router-dom
Enter fullscreen modeExit fullscreen mode

This will help you installReact Router Dom for an efficient routing system.

Build Login Component

We'll start with a simple login component that accepts two inputs: an email field and a password field. When anonChange event occurs, these two input fields trigger thehandleInput function. The name attribute on the input is also used by the function to set the input state. This is an effective method for managing input fields in ReactJS. If the button is pressed, the parent listens for anonSubmit event and invokes thehandleSubmitEvent handler.

import{useState}from"react";constLogin=()=>{const[input,setInput]=useState({username:"",password:"",});consthandleSubmitEvent=(e)=>{e.preventDefault();if(input.username!==""&&input.password!==""){//dispatch action from hooks}alert("please provide a valid input");};consthandleInput=(e)=>{const{name,value}=e.target;setInput((prev)=>({...prev,[name]:value,}));};return(<formonSubmit={handleSubmitEvent}><divclassName="form_control"><labelhtmlFor="user-email">Email:</label><inputtype="email"id="user-email"name="email"placeholder="example@yahoo.com"aria-describedby="user-email"aria-invalid="false"onChange={handleInput}/><divid="user-email"className="sr-only">Pleaseenteravalidusername.Itmustcontainatleast6characters.</div></div><divclassName="form_control"><labelhtmlFor="password">Password:</label><inputtype="password"id="password"name="password"aria-describedby="user-password"aria-invalid="false"onChange={handleInput}/><divid="user-password"className="sr-only">yourpasswordshouldbemorethan6character</div></div><buttonclassName="btn-submit">Submit</button></form>);};exportdefaultLogin;
Enter fullscreen modeExit fullscreen mode

tracylogin
This image shows the output of our login component, which contains two input fields and a button.

Create AuthContext and AuthProvider

Thecontext API is generally used for managing states that will be needed across an application. For example, we need our user data or tokens that are returned as part of the login response in the dashboard components. Also, some parts of our application need user data as well, so making use of the context API is more than solving the problem for us.

Next, in anAuthProvider.js file, create an AuthContext for managing the user state and an AuthProvider for consuming the content of our context.

import{useContext,createContext}from"react";constAuthContext=createContext();constAuthProvider=({children})=>{return<AuthContext.Provider>{children}</AuthContext.Provider>;};exportdefaultAuthProvider;exportconstuseAuth=()=>{returnuseContext(AuthContext);};
Enter fullscreen modeExit fullscreen mode

The code set up above is used for creating the authentication context in React using the Context API. It creates anAuthContext usingcreateContext() to manage the authentication state.

TheAuthProvider component is designed to wrap the application and provide the authentication context to its child components using theAuthContext.Provider.

TheuseAuthcustom hook utilizesuseContext to access the authentication context from within components, allowing them to consume the authentication state and related functions stored in the context. As this article progresses, we will add the authentication logics that control the login and logout processes, passing them via the AuthContext.Provider. You will then have access to them and be able to use them when you call the useAuth function.

Next, import and wrap theAuthProvider around the app content inApp.js.

importAuthProviderfrom"./hooks/AuthProvider";functionApp(){return(<divclassName="App"><AuthProvider>{/* App content */}</AuthProvider></div>);}exportdefaultApp;
Enter fullscreen modeExit fullscreen mode

Now that theAuthProvider has been wrapped around the App components, we can access all the context values in any of our pages or components within the application when we add all the routes needed to the App component.

Create Authentication Logic

Next, the AuthProvider component will be updated with login and logout functions. This function will be passed down through theAuthContext.Provider and it will be accessible globally.

import{useContext,createContext,useState}from"react";import{useNavigate}from"react-router-dom";constAuthContext=createContext();constAuthProvider=({children})=>{const[user,setUser]=useState(null);const[token,setToken]=useState(localStorage.getItem("site")||"");constnavigate=useNavigate();constloginAction=async(data)=>{try{constresponse=awaitfetch("your-api-endpoint/auth/login",{method:"POST",headers:{"Content-Type":"application/json",},body:JSON.stringify(data),});constres=awaitresponse.json();if(res.data){setUser(res.data.user);setToken(res.token);localStorage.setItem("site",res.token);navigate("/dashboard");return;}thrownewError(res.message);}catch(err){console.error(err);}};constlogOut=()=>{setUser(null);setToken("");localStorage.removeItem("site");navigate("/login");};return(<AuthContext.Providervalue={{token,user,loginAction,logOut}}>{children}</AuthContext.Provider>);};exportdefaultAuthProvider;exportconstuseAuth=()=>{returnuseContext(AuthContext);};
Enter fullscreen modeExit fullscreen mode

In this code, theAuthProvider component manages the user authentication state, providing functionalities like login, logout, and token storage usinguseState hooks.

TheloginAction function handles user login by sending aPOST request to an authentication endpoint, updating the user and token state upon a successful response, and storing the token inlocal storage.

ThelogOut function clears user and token data, removing the token from local storage. TheAuthContext.Provider makes the authentication state and related functions available to its child components, accessible via theuseAuth hook, enabling components to consume authentication data and actions within the application.

Protect Routes with Authorization

Next up, we will set up a route guard that protects any route that is private in the application. To achieve this, theuseAuth hook for accessing our context data will be needed. Here is the code on how to work through it.

importReactfrom"react";import{Navigate,Outlet}from"react-router-dom";import{useAuth}from"../hooks/AuthProvider";constPrivateRoute=()=>{constuser=useAuth();if(!user.token)return<Navigateto="/login"/>;return<Outlet/>;};exportdefaultPrivateRoute;
Enter fullscreen modeExit fullscreen mode

This code defines aPrivateRoute component for handling authentication. It utilizes theuseAuth hook from theAuthProvider to access user authentication data. If the user does not possess a token, indicating they are not logged in, the code triggers a redirect to the/login route using the<Navigate> component. Otherwise, it renders the child components nested within thePrivateRoute component accessed via<Outlet />, allowing authenticated users to access the protected routes while redirecting unauthenticated users to the login page.

Add Routing

Next, we will update theApp.js component by adding routing to it. It serves as the root component, enclosing the entire application. Within theApp.js, it uses the Router component to set up the routing mechanism.

import{BrowserRouterasRouter,Route,Routes}from"react-router-dom";importLoginfrom"./components/Login";importDashboardfrom"./components/Dashboard";importAuthProviderfrom"./hooks/AuthProvider";importPrivateRoutefrom"./router/route";functionApp(){return(<divclassName="App"><Router><AuthProvider><Routes><Routepath="/login"element={<Login/>}/><Routeelement={<PrivateRoute/>}><Routepath="/dashboard"element={<Dashboard/>}/></Route>{/* Other routes */}</Routes></AuthProvider></Router></div>);}exportdefaultApp;
Enter fullscreen modeExit fullscreen mode

TheRoutes component establishes the route configuration: the '/login' path is mapped to the Login component, rendering it when the URL matches. The<PrivateRoute /> component serves as a guard for protecting the/dashboard route. When a user navigates to/dashboard, thePrivateRoute checks for authentication using theAuthProvider. If the user is authenticated (has a token), it renders the Dashboard component; otherwise, it redirects to the/login route, ensuring protected access to the dashboard.

API Integration

If you've reached this point, great job! We're nearing the end of this article. Yet there are a few more steps to cover. We've successfully created a login component, established an AuthContext to manage user sessions, and set up a route guard. Now, the next step is to trigger the login action by utilizing theuseAuth hook to access the function. This approach enables thehandleSubmitEvent function in the Login Component to trigger the API request. Upon a successful response, the tokens and user data will be saved and passed down through the AuthContext.

Here is the updated code for the login component.

import{useState}from"react";import{useAuth}from"../hooks/AuthProvider";constLogin=()=>{const[input,setInput]=useState({username:"",password:"",});constauth=useAuth();consthandleSubmitEvent=(e)=>{e.preventDefault();if(input.username!==""&&input.password!==""){auth.loginAction(input);return;}alert("pleae provide a valid input");};return(<formonSubmit={handleSubmitEvent}>{/* Form inputs are provided in the above examples */}</form>);};exportdefaultLogin;
Enter fullscreen modeExit fullscreen mode

The above example shows how to dispatch theloginAction using theuseAuth hook.

Add Logout Button

Next, we need to add a button to dispatch thelogOut action for ending the user session by clearing the user state in the context and also clarifying the token localStorage. Now create a dashboard component and add the code below.

importReact,{useEffect}from"react";import{useAuth}from"../hooks/AuthProvider";constDashboard=()=>{constauth=useAuth();return(<divclassName="container"><div><h1>Welcome!{auth.user?.username}</h1><buttononClick={()=>auth.logOut()}className="btn-submit">logout</button></div></div>);};exportdefaultDashboard;
Enter fullscreen modeExit fullscreen mode

In the code above, the Dashboard component utilizes theuseAuth hook from theAuthProvider to access authentication information. The component displays a welcome message with the username of the logged-in user and a logout button, which triggers thelogOut function to log the user out.
tracylogin
The image above shows two input fields and a button. The user enters the email address and password.
req
This image illustrates the input data being passed as an object to the backend after a user enters their details.
c-2
This image depicts the backend API response data, which includes user data, user tasks, and a token for managing user sessions.
dashboar-test
After logging in successfully, the user is redirected to the dashboard, where the username and logout buttons are displayed.

The images provided illustrate the login process from our implementation. When a user enters the correct information, it sends it to the server as a payload, and the server checks to see if the user exits. If they do, we receive a response with a user object containing all of the user's information, such as name and email address, and they are redirected to the dashboard page. In addition, we receive a token, which is saved to the browser's local storage. This allows us to manage user sessions more effectively. When the user clicks the log-out action, the last action occurs. It clears the user's local storage and redirects them to the login page.

Conclusion

Understanding how to use the Context API and React Router in authentication workflows is critical for managing user sessions in React applications. From creating authentication contexts to creating guarded routes and enabling user actions like login and logout, this comprehensive guide equips developers to handle user authentication seamlessly and securely within their React projects.

Top comments(40)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
petergfernandez profile image
Peter Fernandez
Architect, Consultant and Engineer on all things Customer Identity & Access Management, I've more than 30 years experience designing and developing secure and robust software solutions.
  • Location
    Somerset, UK
  • Pronouns
    he/him/his
  • Work
    Principal Developer Advocate at Auth0 by Okta
  • Joined

Building user authentication and authorization oneself, as part of the development of a project, is an option. And articles like this are a fantastic resource for showing you how; nice work@miracool 😎 However building user authentication and authorization when it's not ones core focus can lead to a whole lot of unnecessary work - that can also open an application to some unwanted and undesirable security implications. Check out my DEV posthere to see how integrating with a SaaS platform - such as Auth0 - can be beneficial for a whole host of reasons 🤗

CollapseExpand
 
xsmobi profile image
Eckard Ritter
  • Joined

Hello Peter,

I have come to this post because I was looking for a solution for a react app, deployed with Netlify, that is easier than with Auth0. The test on localhost works fine. The application is a Single Page Application on Auth0. But now, when I want to use Autho0 for the web version, it becomes rather complicated. On Netlify, I read that I have to create a Machine to Machine application - and its getting complicated.
Therefore I am looking for a solution described here, relying on the power of React.

You write: "However building user authentication and authorization when it's not ones core focus can lead to a whole lot of unnecessary work". And exactly this is my impression with Auth0. I recommend, take the time and read documentation of Netlify & Auth0 with the eyes on someone with no core focus on that stuff.

Best,
Eckard

CollapseExpand
 
petergfernandez profile image
Peter Fernandez
Architect, Consultant and Engineer on all things Customer Identity & Access Management, I've more than 30 years experience designing and developing secure and robust software solutions.
  • Location
    Somerset, UK
  • Pronouns
    he/him/his
  • Work
    Principal Developer Advocate at Auth0 by Okta
  • Joined

Hi Eckard,

Thanks for reaching out 😎

I'm glad to hear you've found integrating your React SPA with Auth0 works well - at least onlocalhost - however, I am sorry to hear you're facing some challenges when using Netlify. I'm not an expert with Netlify per se, but I would recommend you check out our Netlify getting started guides on the Auth0 Developer Centre:developer.auth0.com/resources/get-.... In particular, theBuild your Web Store with React, Auth0, Stripe and Netlify video (with Ben Dechrai, ex Auth0) does a great job of showing you how to integrate Auth0 as part of a React application deployed to Netlify.

I'm also not sure which documentation you read concerning the creation of a Machine-to-Machine (M2M) application 🤔 But I'm guessing it might be the documentation on Netlify that's currently marked as "in beta"? I.e:docs.netlify.com/integrations/auth...? Correct? A Machine-to-Machine application is typically one where there is no user interaction; using the OAuth 2.0/OIDCClient Credentials grant, this is where an application would call an API - such as the Auth0 Management API - in what is a machine-level context.

If you do still find yourself struggling, please feel free to post over in our Community Forum (community.auth0.com/) and mention me in any question you post. Hopefully, we can get you up and running ASAP....and also share what we find with others who may be facing a similar challenge?!

All the best
Peter

Thread Thread
 
xsmobi profile image
Eckard Ritter
  • Joined

the documentation on Netlify that's currently marked as "in beta"?
Yes. Thank you!

Thread Thread
 
xsmobi profile image
Eckard Ritter
  • Joined

Finally, I managed to create a M2M application. But on Netlify it was not possible the configure it. The page URL looks likeapp.netlify.com/sites/xxxxx/integr...

Under this headline
Auth0 by Okta
Easily integrate your Auth0 tenants with Netlify.
Configuration

I did the prefix: REACT_APP_

I selected my tenant

But under
Configure Tenant - dev-t927qb8a
Manage Apps

It was not possible to select the respective app. The select menu did not show me this one. Seemlingly it only showed Single Page Apps but not M2M apps

The end of the story is: I cannot do this. Even if it had worked out now, I think, I cannot use it because I need a clear, reproducible path.

CollapseExpand
 
dsaga profile image
Dusan Petkovic
Front-end software engineer with full-stack experience eager to learn new things to find material for my blog :/
  • Location
    Paracin, Serbia
  • Pronouns
    he/him
  • Joined

Thanks for the article, how would you handle a refresh endpoint call on app start

CollapseExpand
 
miracool profile image
Makanju Oluwafemi
Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Email
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined
• Edited on• Edited

Hi Dusan, Thanks for the feedback! For this app, there's no support for a refresh token on the backend, but I did use a valid endpoint; I just changed it before publishing.
Okay, let's assume there's a refresh token. This is how I will handle it.

  1. Since a token is stored in thelocalStorage , we can check when an app starts to know if a token exists; iftrue, we can attempt to login the user by making a request to the refresh token; otherwise, redirect to the login page.
CollapseExpand
 
blanq_ed profile image
Obiwulu Eric
Aiming for the next big change
  • Location
    Lagos, Nigeria
  • Education
    University of Lagos
  • Work
    Learning
  • Joined

Like for a refresh token?
I think he'll have to write a script to check with the backend if the access token sent is still valid.. if it's not the backend will check for the user with the expired acess token and if the user is found, the refresh route from the backend will be triggered... That's just my idea

CollapseExpand
 
iconicspidey profile image
Big Spidey🕷️
software developer
  • Location
    Abuja, Nigeria
  • Joined

my thoughts

CollapseExpand
 
ngualpha profile image
Ngu Alpha Tangri
Full stack web developer and tech enthusiast. Passionate about Js and PHP projects
  • Joined

Nice post. I am new to react js (actually focused on backend and react native). Your post has really helped me with this auth concept. Its pretty much simillar to what I do in react native. The effort you put in to explain every process to down to the smallest detail is commendable. Thanks again for this. My biggest issue which was using the context API with react routes has been visited here. Now I can rest easy on this.

CollapseExpand
 
miracool profile image
Makanju Oluwafemi
Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Email
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined

Thanks for the kind words

CollapseExpand
 
michaeloye profile image
Michaeloye
  • Joined

Bro oo, Nice article, I like the effort and detail you put into this, nicely done

CollapseExpand
 
its7rishi profile image
Saptarshi Majumdar
  • Joined

Fantastic article. Was stuck with user context for one of my projects, but this article made me understand it better.

CollapseExpand
 
rishi_agrahari_38ae9b2ddc profile image
Rishi Agrahari
  • Joined

Really helpful have simple and easy explanation

CollapseExpand
 
miracool profile image
Makanju Oluwafemi
Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Email
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined

Thanks for the kind words

CollapseExpand
 
david123499 profile image
David
  • Joined
• Edited on• Edited

I'm wondering how you got navigate("/dashboard"); in loginAction() to work? When I run the code, I get an error saying navigate() cannot be run outside of a Route context. I then tried to put navigate() inside a custom hook and call the hook from loginAction(). That didn't work either as a hook can only be called from a react component :(

CollapseExpand
 
miracool profile image
Makanju Oluwafemi
Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Email
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined
• Edited on• Edited

Hi David, thanks for the feedback! From your error, it seems you have not set up your router. To use any react router method, you need to have your router set up properly first.

CollapseExpand
 
david123499 profile image
David
  • Joined

Hey thanks! I had my router setup but there was a small mistake in it. Your comment helped tremendously in finding my problem. I forgot to mention in my first post what a great writeup your article is. Thanks for posting it!

Thread Thread
 
miracool profile image
Makanju Oluwafemi
Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Email
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined

Glad it helped!

CollapseExpand
 
andy98725 profile image
Andy725
  • Joined

Awesome tutorial! Very well written.

Only one question- how would you uselocalStorage more? It's unclear if this is sufficient to store & retrieve the token, and it's definitely going to clear the user model between visits.

CollapseExpand
 
petejames profile image
Peet James
  • Joined

One approach is to store non-sensitive user data in local storage along with the token. AuseEffect hook can also be used to re-fetch the user data associated with the token whenever the components are re-loaded during page refreshes or tab closure

CollapseExpand
 
kansoldev profile image
Yahaya Oyinkansola
I build web apps with React, explaining concepts and code logic to help you understand React better.
  • Location
    Uyo, Nigeria
  • Education
    University of Uyo
  • Joined

This is a nice article Makanju. I didn't really understand most of what you said here though 😂😂, because I haven't yet learnt about the Context API in React. But I have seen this will be very helpful for me going forward, and I have bookmarked it. Thank you!

CollapseExpand
 
miracool profile image
Makanju Oluwafemi
Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Email
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined
• Edited on• Edited

Glad to have helped, cheers!

CollapseExpand
 
anickacodes profile image
Nicki
Junior fswd implementing change
  • Joined

Aaah, great code along. I'm wondering what your server side code looks like ?

CollapseExpand
 
miracool profile image
Makanju Oluwafemi
Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Email
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined

Hi Nicki, Thanks for the feedback, i will share.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Hi there, I'm a frontend engineer / developer relations - I code, I write documentation and I write tech blogs. Do you have something for me? Send me an email.Emerging developer relation engineer
  • Location
    Nigeria
  • Education
    Bsc in Computer science and engineering
  • Pronouns
    He/Him
  • Work
    Frontend Engineer
  • Joined

More fromMakanju Oluwafemi

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp