What Happens When Logged Into a Web Page and You Get Redirected to Login Again

The author selected Creative Commons to receive a donation as part of the Write for DOnations plan.

Introduction

Many web applications are a mix of public and private pages. Public pages are available to anyone, while a private page requires a user login. You can use authentication to manage which users take access to which pages. Your React application will need to handle situations where a user tries to access a private folio before they are logged in, and you will need to save the login information once they accept successfully authenticated.

In this tutorial, you'll create a React awarding using a token-based authentication system. You'll create a mock API that will return a user token, build a login folio that volition fetch the token, and check for authentication without rerouting a user. If a user is not authenticated, you'll provide an opportunity for them to log in and and then allow them to continue without navigating to a dedicated login page. Equally y'all build the application, you'll explore different methods for storing tokens and will learn the security and feel trade-offs for each arroyo. This tutorial will focus on storing tokens in localStorage and sessionStorage.

By the stop of this tutorial, y'all'll be able to add authentication to a React application and integrate the login and token storage strategies into a complete user workflow.

Prerequisites

  • You lot will need a development surround running Node.js; this tutorial was tested on Node.js version 10.22.0 and npm version half-dozen.14.six. To install this on macOS or Ubuntu 18.04, follow the steps in How to Install Node.js and Create a Local Development Environs on macOS or the Installing Using a PPA section of How To Install Node.js on Ubuntu eighteen.04.

  • A React development environment set upward with Create React App, with the non-essential boilerplate removed. To set this up, follow Stride 1 — Creating an Empty Project of the How To Manage State on React Course Components tutorial. This tutorial will utilize auth-tutorial as the project name.

  • Yous will be fetching data from APIs using React. Y'all can learn most working with APIs in How To Call Spider web APIs with the useEffect Hook in React.

  • Y'all will likewise need a basic knowledge of JavaScript, HTML, and CSS, which you can find in our How To Build a Website With HTML series, How To Manner HTML with CSS, and in How To Code in JavaScript.

Footstep ane — Edifice a Login Page

In this step, yous'll create a login page for your application. You'll kickoff by installing React Router and creating components to represent a total application. Then you'll render the login page on whatsoever route then that your users can login to the awarding without being redirected to a new page.

By the cease of this step, you'll have a bones application that will render a login folio when a user is not logged into the awarding.

To begin, install react router with npm. There are ii different versions: a spider web version and a native version for apply with React Native. Install the web version:

                      
  1. npm install react-router-dom

The package will install and you'll receive a message when the installation is consummate. Your message may vary slightly:

                      

Output

... + react-router-dom@v.2.0 added 11 packages from 6 contributors, removed x packages and audited 1945 packages in 12.794s ...

Next, create two components called Dashboard and Preferences to deed as individual pages. These will stand for components that a user should not see until they have successfully logged into the application.

First, create the directories:

                      
  1. mkdir src/components/Dashboard
  2. mkdir src/components/Preferences

And so open Dashboard.js in a text editor. This tutorial will employ nano:

                      
  1. nano src/components/Dashboard/Dashboard.js

Inside of Dashboard.js, add an <h2> tag with the content of Dashboard:

auth-tutorial/src/components/Dashboard/Dashboard.js

                      import            React            from            'react'            ;            export            default            role            Dashboard            (            )            {            render            (            <h2>Dashboard<            /h2>            )            ;            }                  

Save and close the file.

Repeat the same steps for Preferences. Open the component:

                      
  1. nano src/components/Preferences/Preferences.js

Add the content:

auth-tutorial/src/components/Preferences/Preferences.js

                      import            React            from            'react'            ;            export            default            function            Preferences            (            )            {            return            (            <h2>Preferences<            /h2>            )            ;            }                  

Salvage and close the file.

Now that yous have some components, you need to import the components and create routes inside of App.js. Check out the tutorial How To Handle Routing in React Apps with React Router for a full introduction to routing in React applications.

To begin, open App.js:

                      
  1. nano src/components/App/App.js

Then import Dashboard and Preferences past adding the following highlighted code:

auth-tutorial/src/components/App/App.js

                      import            React            from            'react'            ;            import            './App.css'            ;                          import              Dashboard              from              '../Dashboard/Dashboard'              ;                                      import              Preferences              from              '../Preferences/Preferences'              ;                        function            App            (            )            {            return            (            <            >            <            /            >            )            ;            }            export            default            App;                  

Side by side, import BrowserRouter, Switch, and Road from react-router-dom:

auth-tutorial/src/components/App/App.js

                      import            React            from            'react'            ;            import            './App.css'            ;                          import              {              BrowserRouter,              Road,              Switch              }              from              'react-router-dom'              ;                        import            Dashboard            from            '../Dashboard/Dashboard'            ;            import            Preferences            from            '../Preferences/Preferences'            ;            function            App            (            )            {            return            (            <            >            <            /            >            )            ;            }            export            default            App;                  

Add a surrounding <div> with a className of wrapper and an <h1> tag to serve as a template for the application. Be certain that you are importing App.css so that you tin can apply the styles.

Next, create routes for the Dashboard and Preferences components. Add BrowserRouter, and then add together a Switch component as a child. Inside of the Switch, add together a Road with a path for each component:

tutorial/src/components/App/App.js

                      import            React            from            'react'            ;            import            './App.css'            ;            import            {            BrowserRouter,            Route,            Switch            }            from            'react-router-dom'            ;            import            Dashboard            from            '../Dashboard/Dashboard'            ;            import            Preferences            from            '../Preferences/Preferences'            ;            function            App            (            )            {            return                          (                                      <div className=              "wrapper"              >                                      <h1>Application<              /h1>                                      <BrowserRouter>                                      <Switch>                                      <Route path=              "/dashboard"              >                                      <Dashboard              /              >                                      <              /Route>                                      <Road path=              "/preferences"              >                                      <Preferences              /              >                                      <              /Road>                                      <              /Switch>                                      <              /BrowserRouter>                                      <              /div>                                      )              ;                        }            consign            default            App;                  

Save and close the file.

The final step is to add some padding to the master <div> then your component is not directly at the edge of the browser. To practice this, yous will change the CSS.

Open App.css:

                      
  1. nano src/components/App/App.css

Replace the contents with a class of .wrapper with padding of 20px:

auth-tutorial/src/components/App/App.css

                      .wrapper            {            padding            :            20px;            }                  

Relieve and close the file. When you exercise, the browser will reload and you'll find your basic components:

Basic component

Check each of the routes. If y'all visit http://localhost:3000/dashboard, you'll find the dashboard folio:

Dashboard Component

Your routes are working as expected, but there is a slight problem. The route /dashboard should be a protected folio and should not exist viewable by an unauthenticated user. In that location are different ways to handle a private page. For instance, you can create a new route for a login page and utilise React Router to redirect if the user is not logged in. This is a fine arroyo, but the user would lose their route and have to navigate dorsum to the page they originally wanted to view.

A less intrusive option is to generate the login folio regardless of the route. With this arroyo, you'll render a login page if there is non a stored user token and when the user logs in, they'll be on the same road that they initially visited. That means if a user visits /dashboard, they will still be on the /dashboard route after login.

To begin, make a new directory for the Login component:

                      
  1. mkdir src/components/Login

Next, open up Login.js in a text editor:

                      
  1. nano src/components/Login/Login.js

Create a basic form with a submit <button> and an <input> for the username and the countersign. Be sure to set up the input type for the password to password:

auth-tutorial/src/components/Login/Login.js

                      import            React            from            'react'            ;            consign            default            part            Login            (            )            {            return            (            <form>            <label>            <p>Username<            /p>            <input type=            "text"            /            >            <            /characterization>            <label>            <p>Password<            /p>            <input type=            "password"            /            >            <            /characterization>            <div>            <push button blazon=            "submit"            >Submit<            /button>            <            /div>            <            /form>            )            }                  

For more than on forms in React, bank check out the tutorial How To Build Forms in React.

Next, add an <h1> tag request the user to log in. Wrap the <form> and the <h1> in a <div> with a className of login-wrapper. Finally, import Login.css:

auth-tutorial/src/components/Login/Login.js

                      import            React            from            'react'            ;                          import              './Login.css'              ;                        export            default            function            Login            (            )            {            render            (                          <div className=              "login-wrapper"              >                                      <h1>Please Log In<              /h1>                        <form>            <label>            <p>Username<            /p>            <input type=            "text"            /            >            <            /characterization>            <characterization>            <p>Countersign<            /p>            <input type=            "password"            /            >            <            /label>            <div>            <button blazon=            "submit"            >Submit<            /button>            <            /div>            <            /form>                          <              /div>                        )            }                  

Relieve and close the file.

Now that you have a basic Login component, you'll need to add some styling. Open Login.css:

                      
  1. nano src/components/Login/Login.css

Center the component on the page by adding a display of flex, and so setting the flex-direction to column to align the elements vertically and calculation align-items to center to brand the component centered in the browser:

auth-tutorial/src/components/Login/Login.css

                      .login-wrapper            {            display            :            flex;            flex-direction            :            cavalcade;            align-items            :            center;            }                  

For more information on using Flexbox, see our CSS Flexbox Cheatsheet

Salve and close the file.

Finally, you'll need to render it inside of App.js if there is no user token. Open App.js:

                      
  1. nano src/components/App/App.js

In Step 3, y'all'll explore options for storing the token. For now, you tin shop the token in memory using the useState Claw.

Import useState from react, then call useState and set render values to token and setToken:

auth-tutorial/src/components/App/App.js

                      import            React              ,              {              useState              }                        from            'react'            ;            import            {            BrowserRouter,            Route,            Switch            }            from            'react-router-dom'            ;            import            './App.css'            ;            import            Dashboard            from            '../Dashboard/Dashboard'            ;            import            Preferences            from            '../Preferences/Preferences'            ;            function            App            (            )            {                          const              [token,              setToken]              =              useState              (              )              ;                        render            (            <div className=            "wrapper"            >            <h1>Awarding<            /h1>            <BrowserRouter>            <Switch>            <Route path=            "/dashboard"            >            <Dashboard            /            >            <            /Road>            <Route path=            "/preferences"            >            <Preferences            /            >            <            /Road>            <            /Switch>            <            /BrowserRouter>            <            /div>            )            ;            }            export            default            App;                  

Import the Login component. Add a conditional statement to display Login if the token is falsy.

Pass the setToken function to the Login component:

auth-tutorial/src/components/App/App.js

                      import            React,            {            useState            }            from            'react'            ;            import            {            BrowserRouter,            Route,            Switch            }            from            'react-router-dom'            ;            import            './App.css'            ;            import            Dashboard            from            '../Dashboard/Dashboard'            ;                          import              Login              from              '../Login/Login'              ;                        import            Preferences            from            '../Preferences/Preferences'            ;            function            App            (            )            {            const            [token,            setToken]            =            useState            (            )            ;                          if              (              !token)              {                                      render              <Login setToken=              {setToken}              /              >                                      }                        return            (            <div className=            "wrapper"            >            <h1>Application<            /h1>            <BrowserRouter>            <Switch>            <Route path=            "/dashboard"            >            <Dashboard            /            >            <            /Route>            <Route path=            "/preferences"            >            <Preferences            /            >            <            /Route>            <            /Switch>            <            /BrowserRouter>            <            /div>            )            ;            }            export            default            App;                  

For at present, there is no token; in the next step, yous'll call an API and set the token with the return value.

Save and shut the file. When you lot do, the browser will reload and you'll see the login folio. Find that if you visit http://localhost:3000/dashboard, you'll yet find the login page since the token has not yet been set up:

Login page

In this footstep, you created an application with individual components and a login component that will display until you ready a token. You also configured routes to display the pages and added a bank check to display the Login component on every route if the user is not yet logged into the application.

In the next pace, you'll create a local API that volition return a user token. You'll phone call the API from the Login component and relieve the token to retentiveness on success.

Step ii — Creating a Token API

In this step, yous'll create a local API to fetch a user token. You'll build a mock API using Node.js that will render a user token. Y'all'll and then call that API from your login page and return the component after you lot successfully retrieve the token. By the end of this step, you lot'll have an application with a working login folio and protected pages that will simply be attainable after login.

You are going to need a server to act as a backend that will render the token. You tin can create a server quickly using Node.js and the Express web framework. For a detailed introduction to creating an Express server, see the tutorial Basic Limited Server in Node.js.

To start, install limited. Since the server is non a requirement of the terminal build, be certain to install as a devDependency.

You'll also demand to install cors. This library volition enable cross origin resource sharing for all routes.

Warning: Practice not enable CORS for all routes in a product application. This can lead to security vulnerabilities.

                      
  1. npm install --save-dev limited cors

When the installation is consummate, yous'll receive a success bulletin:

                      

Output

... + cors@2.8.five + express@4.17.1 removed 10 packages, updated 2 packages and audited 2059 packages in 12.597s ...

Side by side, open a new file chosen server.js in the root of your application. Do not add together this file to the /src directory since you exercise not want information technology to be function of the final build.

                      
  1. nano server.js

Import express, then initialize a new app by calling express() and saving the result to a variable called app:

auth-tutorial/server.js

                      const            express            =            require            (            'express'            )            ;            const            app            =            express            (            )            ;                  

Later on creating the app, add together cors as a middleware. First, import cors, and then add together it to the application by calling the use method on app:

auth-tutorial/server.js

                      const            express            =            require            (            'express'            )            ;                          const              cors              =              require              (              'cors'              )              ;                        const            app            =            express            (            )            ;            app.              use              (              cors              (              )              )              ;                              

Side by side, listen to a specific route with app.use. The showtime argument is the path the awarding will listen to and the 2nd statement is a callback part that will run when the application serves the path. The callback takes a req argument, which contains the asking information and a res statement that handles the result.

Add together in a handler for the /login path. Call res.ship with a JavaScript object containing a token:

auth-tutorial/server.js

                      const            express            =            require            (            'limited'            )            ;            const            cors            =            require            (            'cors'            )            const            app            =            express            (            )            ;            app.            use            (            cors            (            )            )            ;            app.              use              (              '/login'              ,              (              req,                res              )              =>              {                        res.              transport              (              {                                      token              :              'test123'                                      }              )              ;                                      }              )              ;                              

Finally, run the server on port 8080 using app.heed:

auth-tutorial/server.js

                      const            express            =            require            (            'express'            )            ;            const            cors            =            crave            (            'cors'            )            const            app            =            express            (            )            ;            app.            apply            (            cors            (            )            )            ;            app.            utilise            (            '/login'            ,            (            req,              res            )            =>            {            res.            send            (            {            token            :            'test123'            }            )            ;            }            )            ;            app.              listen              (              8080              ,              (              )              =>              console.              log              (              'API is running on http://localhost:8080/login'              )              )              ;                              

Save and shut the file. In a new terminal window or tab, outset the server:

                      
  1. node server.js

You volition receive a response indicating that the server is starting:

                      

Output

API is running on http://localhost:8080/login

Visit http://localhost:8080/login and you'll discover your JSON object.

Token response

When you fetch the token in your browser, you are making a Go request, merely when yous submit the login form you lot will be making a Post request. That's not a problem. When you set up your route with app.use, Express volition handle all requests the same. In a production awarding, you lot should be more specific and merely let certain request methods for each road.

Now that you accept a running API server, you demand to make a request from your login folio. Open Login.js:

                      
  1. nano src/components/Login/Login.js

In the previous step, you passed a new prop called setToken to the Login component. Add together in the PropType from the new prop and destructure the props object to pull out the setToken prop.

auth-tutorial/src/components/Login/Login.js

                      import            React            from            'react'            ;                          import              PropTypes              from              'prop-types'              ;                        import            './Login.css'            ;            export            default            function            Login            (                                          {                setToken                }                                      )            {            return            (            <div className=            "login-wrapper"            >            <h1>Please Log In<            /h1>            <form>            <characterization>            <p>Username<            /p>            <input type=            "text"            /            >            <            /label>            <characterization>            <p>Password<            /p>            <input blazon=            "countersign"            /            >            <            /characterization>            <div>            <button type=            "submit"            >Submit<            /button>            <            /div>            <            /form>            <            /div>            )            }            Login.propTypes              =              {                                      setToken              :              PropTypes.func.isRequired                          }                              

Next, create a local country to capture the Username and Password. Since yous do non need to manually set data, make the <inputs> uncontrolled components. Yous can notice detailed data about uncontrolled components in How To Build Forms in React.

auth-tutorial/src/components/Login/Login.js

                      import            React              ,              {              useState              }                        from            'react'            ;            import            PropTypes            from            'prop-types'            ;            import            './Login.css'            ;            export            default            role            Login            (                          {              setToken              }                        )            {                          const              [username,              setUserName]              =              useState              (              )              ;                                      const              [countersign,              setPassword]              =              useState              (              )              ;                        return            (            <div className=            "login-wrapper"            >            <h1>Please Log In<            /h1>            <form>            <label>            <p>Username<            /p>            <input type=            "text"            onChange=              {              e              =>              setUserName              (e.target.value)              }                        /            >            <            /label>            <label>            <p>Password<            /p>            <input type=            "password"            onChange=              {              east              =>              setPassword              (e.target.value)              }                        /            >            <            /label>            <div>            <button blazon=            "submit"            >Submit<            /button>            <            /div>            <            /class>            <            /div>            )            }            Login.propTypes            =            {            setToken            :            PropTypes.func.isRequired            }            ;                  

Adjacent, create a part to make a Mail asking to the server. In a big application, you would add together these to a separate directory. In this example, you'll add together the service direct to the component. Check out the tutorial How To Telephone call Web APIs with the useEffect Hook in React for a detailed look at calling APIs in React components.

Create an async function called loginUser. The function will have credentials as an argument, then information technology will call the fetch method using the Mail service option:

auth-tutorial/src/components/Login/Login.js

                      import            React,            {            useState            }            from            'react'            ;            import            PropTypes            from            'prop-types'            ;            import            './Login.css'            ;                          async              function              loginUser              (              credentials              )              {                                      render              fetch              (              'http://localhost:8080/login'              ,              {                                      method              :              'POST'              ,                                      headers              :              {                                      'Content-Blazon'              :              'application/json'                                      }              ,                                      body              :              JSON              .              stringify              (credentials)                                      }              )                                      .              then              (              data              =>              information.              json              (              )              )                                      }                        export            default            function            Login            (                          {              setToken              }                        )            {            ...                  

Finally, create a grade submit handler called handleSubmit that volition call loginUser with the username and password. Call setToken with a successful result. Call handleSubmit using the onSubmit result handler on the <course>:

auth-tutorial/src/components/Login/Login.js

                      import            React,            {            useState            }            from            'react'            ;            import            PropTypes            from            'prop-types'            ;            import            './Login.css'            ;            async            office            loginUser            (            credentials            )            {            render            fetch            (            'http://localhost:8080/login'            ,            {            method            :            'Postal service'            ,            headers            :            {            'Content-Type'            :            'application/json'            }            ,            trunk            :            JSON            .            stringify            (credentials)            }            )            .            and so            (            data            =>            data.            json            (            )            )            }            export            default            function            Login            (                          {              setToken              }                        )            {            const            [username,            setUserName]            =            useState            (            )            ;            const            [password,            setPassword]            =            useState            (            )            ;                          const              handleSubmit              =              async              e              =>              {                        e.              preventDefault              (              )              ;                                      const              token              =              await              loginUser              (              {                        username,                        countersign                          }              )              ;                                      setToken              (token)              ;                                      }                        return            (            <div className=            "login-wrapper"            >            <h1>Please Log In<            /h1>            <course            onSubmit=              {handleSubmit}                        >            <label>            <p>Username<            /p>            <input type=            "text"            onChange=            {            e            =>            setUserName            (east.target.value)            }            /            >            <            /label>            <characterization>            <p>Password<            /p>            <input type=            "password"            onChange=            {            e            =>            setPassword            (due east.target.value)            }            /            >            <            /label>            <div>            <push type=            "submit"            >Submit<            /push button>            <            /div>            <            /form>            <            /div>            )            }            Login.propTypes            =            {            setToken            :            PropTypes.func.isRequired            }            ;                  

Save and close the file. Make sure that your local API is still running, and then open up a browser to http://localhost:3000/dashboard.

You volition see the login folio instead of the dashboard. Fill out and submit the class and you will receive a web token so redirect to the folio for the dashboard.

Login page

You lot now have a working local API and an application that requests a token using a username and password. But in that location is still a trouble. The token is currently stored using a local state, which means that it is stored in JavaScript memory. If you open a new window, tab, or even simply refresh the page, yous will lose the token and the user will need to login again. This volition exist addressed in the next pace.

In this step you created a local API and a login page for your application. You learned how to create a Node server to send a token and how to telephone call the server and store the token from a login component. In the adjacent step, you'll acquire how to store the user token so that a session will persist across page refreshes or tabs.

Step three — Storing a User Token with sessionStorage and localStorage

In this step, you lot'll shop the user token. You'll implement different token storage options and acquire the security implications of each arroyo. Finally, you'll larn how different approaches volition change the user experience as the user opens new tabs or closes a session.

By the end of this footstep, you'll be able to choose a storage approach based on the goals for your application.

There are several options for storing tokens. Every option has costs and benefits. In brief the options are: storing in JavaScript retentivity, storing in sessionStorage, storing in localStorage, and storing in a cookie. The main trade-off is security. Whatsoever information that is stored exterior of the memory of the current awarding is vulnerable to Cantankerous-Site Scripting (XSS) attacks. The danger is that if a malicious user is able to load code into your application, it can access localStorage, sessionStorage, and whatsoever cookie that is too accessible to your awarding. The do good of the non-memory storage methods is that you can reduce the number of times a user will need to log in to create a improve user experience.

This tutorial will comprehend sessionStorage and localStorage, since these are more modernistic than using cookies.

Session Storage

To test the benefits of storing exterior of retention, convert the in-memory storage to sessionStorage. Open up App.js:

                      
  1. nano src/components/App/App.js

Remove the phone call to useState and create ii new functions chosen setToken and getToken. Then call getToken and assign the results to a variable called token:

auth-tutorial/src/components/App/App.js

                      import            React            from            'react'            ;            import            {            BrowserRouter,            Route,            Switch            }            from            'react-router-dom'            ;            import            './App.css'            ;            import            Dashboard            from            '../Dashboard/Dashboard'            ;            import            Login            from            '../Login/Login'            ;            import            Preferences            from            '../Preferences/Preferences'            ;                          office              setToken              (              userToken              )              {                                      }                                      function              getToken              (              )              {                                      }                        role            App            (            )            {                          const              token              =              getToken              (              )              ;                        if            (            !token)            {            return            <Login setToken=            {setToken}            /            >            }            return            (            <div className=            "wrapper"            >            ...            <            /div>            )            ;            }            export            default            App;                  

Since y'all are using the aforementioned role and variable names, you will not need to change any code in the Login component or the remainder of the App component.

Within of setToken, salve the userToken argument to sessionStorage using the setItem method. This method takes a key equally a beginning argument and a string equally the second argument. That ways you'll need to convert the userToken from an object to a string using the JSON.stringify function. Phone call setItem with a cardinal of token and the converted object.

auth-tutorial/src/components/App/App.js

                      import            React            from            'react'            ;            import            {            BrowserRouter,            Route,            Switch            }            from            'react-router-dom'            ;            import            './App.css'            ;            import            Dashboard            from            '../Dashboard/Dashboard'            ;            import            Login            from            '../Login/Login'            ;            import            Preferences            from            '../Preferences/Preferences'            ;            function            setToken            (            userToken            )            {            sessionStorage.              setItem              (              'token'              ,              JSON              .              stringify              (userToken)              )              ;                        }            role            getToken            (            )            {            }            function            App            (            )            {            const            token            =            getToken            (            )            ;            if            (            !token)            {            return            <Login setToken=            {setToken}            /            >            }            return            (            <div className=            "wrapper"            >            ...            <            /div>            )            ;            }            export            default            App;                  

Salvage the file. When you do the browser will reload. If you type in a username and password and submit, the browser volition nonetheless render the login page, simply if you look inside your browser console tools, you'll notice the token is stored in sessionStorage. This image is from Firefox, just you'll find the aforementioned results in Chrome or other modern browsers.

Token in sessionStorage

At present yous need to retrieve the token to return the right page. Inside the getToken function, telephone call sessionStorage.getItem. This method takes a key as an statement and returns the string value. Catechumen the string to an object using JSON.parse, then render the value of token:

auth-tutorial/src/components/App/App.js

                      import            React            from            'react'            ;            import            {            BrowserRouter,            Road,            Switch            }            from            'react-router-dom'            ;            import            './App.css'            ;            import            Dashboard            from            '../Dashboard/Dashboard'            ;            import            Login            from            '../Login/Login'            ;            import            Preferences            from            '../Preferences/Preferences'            ;            function            setToken            (            userToken            )            {            sessionStorage.            setItem            (            'token'            ,            JSON            .            stringify            (userToken)            )            ;            }            part            getToken            (            )            {                          const              tokenString              =              sessionStorage.              getItem              (              'token'              )              ;                                      const              userToken              =              JSON              .              parse              (tokenString)              ;                                      return              userToken?.token            }            office            App            (            )            {            const            token            =            getToken            (            )            ;            if            (            !token)            {            return            <Login setToken=            {setToken}            /            >            }            render            (            <div className=            "wrapper"            >            ...            <            /div>            )            ;            }            export            default            App;                  

You need to utilize the optional chaining operator—?.—when accessing the token property because when you first access the application, the value of sessionStorage.getItem('token') volition exist undefined. If you endeavor to admission a property, you will generate an mistake.

Relieve and close the file. In this case, y'all already have a token stored, and then when the browser refreshes, yous will navigate to the private pages:

Dashboard

Articulate out the token by either deleting the token in the Storage tab in your developer tools or by typing sessionStorage.articulate() in your developer console.

In that location's a fiddling problem at present. When y'all log in, the browser saves the token, only y'all still meet the login page.

Token stored still not logged in

The trouble is your code never alerts React that the token retrieval was successful. Yous'll still need to gear up some country that will trigger a re-render when the information changes. Similar near problems in React, there are multiple ways to solve it. One of the most elegant and reusable is to create a custom Hook.

Creating a Custom Token Hook

A custom Hook is a function that wraps custom logic. A custom Hook usually wraps one or more built-in React Hooks along with custom implementations. The main reward of a custom Hook is that you lot can remove the implementation logic from the component and you can reuse it beyond multiple components.

By convention, custom Hooks start with the keyword utilize*.

Open a new file in the App directory called useToken.js:

                      
  1. nano src/components/App/useToken.js

This will exist a small Hook and would be fine if y'all defined it straight in App.js. But moving the custom Hook to a different file will show how Hooks work outside of a component. If yous start to reuse this Claw across multiple components, you lot might too desire to move it to a carve up directory.

Within useToken.js, import useState from react. Notice that you do not demand to import React since you will have no JSX in the file. Create and consign a function called useToken. Inside this function, utilize the useState Hook to create a token state and a setToken function:

auth-tutorial/src/components/App/useToken.js

                      import            {            useState            }            from            'react'            ;            export            default            function            useToken            (            )            {            const            [token,            setToken]            =            useState            (            )            ;            }                  

Side by side, re-create the getToken function to useHook and catechumen it to an arrow office, since you placed it within useToken. You could leave the function as a standard, named role, just it can be easier to read when top-level functions are standard and internal functions are arrow functions. Notwithstanding, each team will be dissimilar. Cull 1 style and stick with information technology.

Place getToken before the state declaration, and so initialize useState with getToken. This will fetch the token and set it as the initial country:

auth-tutorial/src/components/App/useToken.js

                      import            {            useState            }            from            'react'            ;            export            default            function            useToken            (            )            {                          const              getToken              =              (              )              =>              {                                      const              tokenString              =              sessionStorage.              getItem              (              'token'              )              ;                                      const              userToken              =              JSON              .              parse              (tokenString)              ;                                      return              userToken?.token                          }              ;                        const            [token,            setToken]            =            useState            (                          getToken              (              )                        )            ;            }                  

Next, copy the setToken function from App.js. Catechumen to an pointer function and proper name the new function saveToken. In addition to saving the token to sessionStorage, save the token to state by calling setToken:

auth-tutorial/src/components/App/useToken.js

                      import            {            useState            }            from            'react'            ;            export            default            function            useToken            (            )            {            const            getToken            =            (            )            =>            {            const            tokenString            =            sessionStorage.            getItem            (            'token'            )            ;            const            userToken            =            JSON            .            parse            (tokenString)            ;            return            userToken?.token            }            ;            const            [token,            setToken]            =            useState            (            getToken            (            )            )            ;                          const              saveToken              =              userToken              =>              {                        sessionStorage.              setItem              (              'token'              ,              JSON              .              stringify              (userToken)              )              ;                                      setToken              (userToken.token)              ;                                      }              ;                        }                  

Finally, return an object that contains the token and saveToken set to the setToken property proper noun. This volition give the component the same interface. Yous can also return the values every bit an assortment, only an object volition requite users a risk to destructure only the values they want if yous reuse this in some other component.

auth-tutorial/src/components/App/useToken.js

                      import            {            useState            }            from            'react'            ;            export            default            part            useToken            (            )            {            const            getToken            =            (            )            =>            {            const            tokenString            =            sessionStorage.            getItem            (            'token'            )            ;            const            userToken            =            JSON            .            parse            (tokenString)            ;            return            userToken?.token            }            ;            const            [token,            setToken]            =            useState            (            getToken            (            )            )            ;            const            saveToken            =            userToken            =>            {            sessionStorage.            setItem            (            'token'            ,            JSON            .            stringify            (userToken)            )            ;            setToken            (userToken.token)            ;            }            ;                          render              {                                      setToken              :              saveToken,                        token                          }                        }                  

Salve and close the file.

Next, open App.js:

                      
  1. nano src/components/App/App.js

Remove the getToken and setToken functions. Then import useToken and telephone call the role destructuring the setToken and token values. You tin can also remove the import of useState since you are no longer using the Hook:

auth-tutorial/src/components/App/App.js

                      import            React            from            'react'            ;            import            {            BrowserRouter,            Road,            Switch            }            from            'react-router-dom'            ;            import            './App.css'            ;            import            Dashboard            from            '../Dashboard/Dashboard'            ;            import            Login            from            '../Login/Login'            ;            import            Preferences            from            '../Preferences/Preferences'            ;                          import              useToken              from              './useToken'              ;                        function            App            (            )            {                          const              {              token,              setToken              }              =              useToken              (              )              ;                        if            (            !token)            {            return            <Login setToken=            {setToken}            /            >            }            return            (            <div className=            "wrapper"            >            <h1>Awarding<            /h1>            <BrowserRouter>            <Switch>            <Route path=            "/dashboard"            >            <Dashboard            /            >            <            /Route>            <Route path=            "/preferences"            >            <Preferences            /            >            <            /Route>            <            /Switch>            <            /BrowserRouter>            <            /div>            )            ;            }            export            default            App;                  

Save and shut the file. When you do, the browser will refresh, and when you lot log in, you will immediately become to the page. This is happening because y'all are calling useState in your custom Hook, which will trigger a component re-render:

Login immediately

Yous at present have a custom Hook to store your token in sessionStorage. At present yous can refresh your page and the user will remain logged in. Just if you attempt to open the awarding in some other tab, the user will be logged out. sessionStorage belongs merely to the specific window session. Any data volition non be available in a new tab and volition be lost when the active tab is closed. If you want to save the token beyond tabs, you'll need to convert to localStorage.

Using localStorage to Save Information Across Windows

Dissimilar sessionStorage, localStorage will save data even after the session ends. This can be more convenient, since it lets users open up multiple windows and tabs without a new login, but it does have some security problems. If the user shares their calculator, they volition remain logged in to the awarding even though they shut the browser. Information technology volition be the user's responsibleness to explicitly log out. The adjacent user would have immediate admission to the application without a login. It'south a risk, but the convenience may be worth information technology for some applications.

To convert to localStorage, open up useToken.js:

                      
  1. nano src/components/App/useToken.js

Then change every reference of sessionStorage to localStorage. The methods you call will be the aforementioned:

auth-tutorial/src/components/App/useToken.js

                      import            {            useState            }            from            'react'            ;            export            default            office            useToken            (            )            {            const            getToken            =            (            )            =>            {            const            tokenString            =            localStorage            .            getItem            (            'token'            )            ;            const            userToken            =            JSON            .            parse            (tokenString)            ;            return            userToken?.token            }            ;            const            [token,            setToken]            =            useState            (            getToken            (            )            )            ;            const            saveToken            =            userToken            =>            {            localStorage            .            setItem            (            'token'            ,            JSON            .            stringify            (userToken)            )            ;            setToken            (userToken.token)            ;            }            ;            render            {            setToken            :            saveToken,            token            }            }                  

Save the file. When yous do, the browser will refresh. You lot volition demand to log in again since there is no token yet in localStorage, but subsequently yous do, you lot will remain logged in when yous open up a new tab.

Still logged into tab

In this pace, you lot saved tokens with sessionStorage and localStorage. Yous also created a custom Hook to trigger a component re-render and to motility component logic to a separate function. Yous besides learned nearly how sessionStorage and localStorage affect the user'due south ability to start new sessions without login.

Conclusion

Authentication is a crucial requirement of many applications. The mixture of security concerns and user experience can be intimidating, but if you focus on validating data and rendering components at the correct fourth dimension, it can become a lightweight process.

Each storage solution offers distinct advantages and disadvantages. Your choice may change as your awarding evolves. By moving your component logic into an abstruse custom Hook, you give yourself the ability to refactor without disrupting existing components.

If you would like to read more React tutorials, check out our React Topic page, or return to the How To Code in React.js series page.

evansreplignigh.blogspot.com

Source: https://www.digitalocean.com/community/tutorials/how-to-add-login-authentication-to-react-applications

0 Response to "What Happens When Logged Into a Web Page and You Get Redirected to Login Again"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel