5

I'm learning Full Stack Development with Spring Boot 2.0 and React . The authentication and authorization are managed by JWT and the app works as expected except I have to re-login after I refresh the browser. How to maintain JWT token even after browser refresh ?

import React, { Component } from 'react';
    import TextField from '@material-ui/core/TextField';
    import Button from '@material-ui/core/Button';
    import Snackbar from '@material-ui/core/Snackbar';
    import Carlist from './Carlist';
    import {SERVER_URL} from '../constants.js';

    class Login extends Component {
      constructor(props) {
        super(props);
        this.state = {username: '', password: '', isAuthenticated: false, open: false};
      }

      logout = () => {
        sessionStorage.removeItem("jwt");
        this.setState({isAuthenticated: false});
    }

      login = () => {
        const user = {username: this.state.username, password: this.state.password};
        fetch(SERVER_URL + 'login', {
          method: 'POST',
          body: JSON.stringify(user)
        })
        .then(res => {
          const jwtToken = res.headers.get('Authorization');
          if (jwtToken !== null) {
            sessionStorage.setItem("jwt", jwtToken);
            this.setState({isAuthenticated: true});
          }
          else {
            this.setState({open: true});  // maintient snackbar ouvert
          }
        })
        .catch(err => console.error(err))
      }

      handleChange = (event) => {
        this.setState({[event.target.name] : event.target.value});
      }

      handleClose = (event) => {
        this.setState({ open: false });
      }

      render() {
        if (this.state.isAuthenticated === true) {
          return (<Carlist />)
        }
        else {
          return (
            <div>
              <br/>
              <TextField tpye="text" name="username" placeholder="Username"
              onChange={this.handleChange} /><br/>
              <TextField type="password" name="password" placeholder="Password"
              onChange={this.handleChange} /><br /><br/>
              <Button variant="raised" color="primary" onClick={this.login}>Login</Button>
              <Snackbar
              open={this.state.open}  onClose={this.handleClose}
              autoHideDuration={1500} message='Check your username and password' />
            </div>
          );
        }
      }
    }

    export default Login;
AchillesVan
  • 4,156
  • 3
  • 35
  • 47

2 Answers2

4

I think you simply don't check for the token in local storage in your constructor. When you reload the page, your constructor executes and sets isAuthenticated = false, whether there is a token in local storage or not. You should add additional logic to check the token in local storage before finally setting isAuthenticated. Probably the best place to put this code would be componentDidMount() function. I mean set it initially to false and then update in componentDidMount() according to current authorization status. Have a look at my GitHub, I have a small boilerplate project with such auth flow set-up. Hope this helps, happy coding!

Georgy Nemtsov
  • 786
  • 1
  • 8
  • 19
-3

I would use local storage instead of session storage like this

localStorage.setItem("jwt", jwtToken)

instead of the line

sessionStorage.setItem("jwt", jwtToken);

The check the local storage in the dev console, refresh the page and see if it is still there. It may require some other changes in your auth flow to build it off localStorage instead of sessionStorage; however, this will solve the immediate problem of losing the jwt on page refresh.

Josh
  • 20
  • 4
  • The local storage (bearer) is still in the dev console but app redirects to the login page. – AchillesVan Oct 19 '18 at 15:53
  • Hi, after I logging in my server handles the redirect. I just checked my express server and ```res.redirect(`http://www.localhost:3001/`);``` that is the line I have that handles the redirection to my landing page as opposed to the sign in page. – Josh Oct 19 '18 at 18:45
  • This is not secure. See section Token Storage on the Client Side - https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#token-storage-on-client-side – user521990 May 26 '21 at 01:42
  • Storing tokens in sessionStorage or localStorage makes your token subject to XSS attacks - localStorage means the vulnerability will be there persistently, so don't do this! – Midiman Jul 07 '23 at 11:47