Unwanted return to login when I refresh the page?

Viewed 131

I have a problem managing the authentication in my app, it's actually working but the problem is that when I refresh the page I am redirected to the Login page even if I am not signed out ! Here is the code of the routes page :

export const fakeAuth = {
  isAuthenticated: false,
  authenticate(cb) {
    this.isAuthenticated = true
    setTimeout(cb, 1000)
  },
  signout(cb) {
    this.isAuthenticated = false
    setTimeout(cb, 1000)
  }
}

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={(props) => (
    fakeAuth.isAuthenticated === true
      ? <Component {...props} />
      : <Redirect to={{
        pathname: '/login',
        state: { from: props.location }
      }} />
  )} />
)

ReactDOM.render(
  <Router history={hist}>
    <Switch>
      <Route path="/login" component={Login} />
      <PrivateRoute path="/admin" component={AdminLayout} />
      <Redirect to="/admin/dashboard" />
    </Switch>
  </Router>,
  document.getElementById("root")
);

And here is the code of the Login component :

export class Login extends Component {
    state = {
        email: '',
        password: '',
        redirectToReferrer: false,
    }

    async login() {
        const email = this.state.email
        const password = this.state.password
        await fakeAuth.authenticate(() => {
            this.setState({
                redirectToReferrer: true
            })
        })

        /*axios.post(`${API_URL}login`, { email, password })
            .then(async (response) => {
                this.setState({
                    redirectToReferrer: true
                })
                //alert(response.data.admin.email + " est connecté !")
                           })*/
    }

    render() {
        const { from } = this.props.location.state || { from: { pathname: '/admin' } }
        console.log(from)
        if (this.state.redirectToReferrer === true) {
            return <Redirect to={from} />
        }
        return (
            <>
                <PanelHeader size="sm" />
                <div className="content">
                    <Row>
                        <Col md="3"></Col>
                        <Col md="6">
                            <Card>
                                <CardHeader>
                                    <h1 className="title"
                                        style={{ textAlign: "center" }}
                                    >Login</h1>
                                </CardHeader>
                                <CardBody>
                                    <Form>
                                        <Row>
                                            <Col md="12">
                                                <FormGroup>
                                                    <h6>Email</h6>
                                                    <Input
                                                        placeholder="Email"
                                                        type="email"
                                                        required
                                                        onChange={(e) => {
                                                            var email = e.target.value
                                                            this.setState({ email: email })
                                                        }}
                                                    />
                                                </FormGroup>
                                            </Col>
                                        </Row>
                                        <Row>
                                            <Col md="12">
                                                <FormGroup>
                                                    <h6>Mot de passe</h6>
                                                    <Input
                                                        placeholder="Mot de passe"
                                                        type="password"
                                                        onChange={(e) => {
                                                            var password = e.target.value
                                                            this.setState({ password: password })
                                                        }}
                                                    />
                                                </FormGroup>
                                            </Col>
                                        </Row>
                                        <Row>
                                            <Col md="12">
                                                <FormGroup style={{ left: "40%" }}>
                                                    <Button outline color="info" size="lg"
                                                        onClick={this.login.bind(this)} className="btn-round">Login</Button>
                                                </FormGroup>
                                            </Col>
                                        </Row>
                                    </Form>
                                </CardBody>
                            </Card>
                        </Col>
                        <Col md="3"></Col>
                    </Row>
                </div>
            </>
        )
    }
}

Any ideas, what should I do ?

1 Answers

You need to save your authenticated state somewhere and check against it when your app is loaded. React is a frontend framework and if you reload your app then it will return to the default state because the framework has no way of saving a persistent state through reloads so it is like you are showing up to your app for the first time. There are several different ways to go about this but the easiest ones are either localStorage or a cookie.

When you authenticate you can save to localStorage like so:

async login() {
    const email = this.state.email
    const password = this.state.password

    await fakeAuth.authenticate(() => {
        //Set an item to browsers localStorage
        localStorage.setItem("Auth", "Your auth state here");

        this.setState({
            redirectToReferrer: true
        })
    })
}

You then can check localStorage when your app loads to see if a user is logged in like so:

localStorage.getItem('Auth');

You can read about the browsers localStorage here Browsers LocalStorage

FYI: I realize that you are in the beginning stages of setting up authentication but normally you would pass an authentication token or session token from your backend and then check that token for each route to make sure a user is logged in. Just stating a user is logged in on the frontend is incredibly insecure. Each route should be protected with some type of authentication measure. You may want to look into Json Web Tokens or something like that. Then you could pass a token to your front end and save that token to localStoage. Then when your app loads you can check this token to see if a user is authenticated or not and check for a valid token for each route.

Related