1

React beginner here and to SPAs in general. I'm trying to make my login state persistent across my app but I struggle with when the user refreshes the page. Currently I have a method in my login form that calls the server to login and I guess receives a cookie (I'm using Flask with the Flask-Login extension). So I thought a simple thing which I've seen in a couple examples is to store the loggedIn state in my parent <App> component like this:

    constructor() {
        super();
        this.state = {
            loggedIn: false
        }
    }

    logIn = () => {
        this.setState({
            loggedIn: true
        });
    };

And then pass the loggedIn state and the logIn() callback down to the login form. This works fine, but after refresh the loggedIn state is false again, obviously. Is using the way to do it? If so, how?

Thanks for your help.

EDIT: After a bunch of research I realized that Flask-Login is (obviously) a server-side session authentication scheme or whatever. So the cookie it sends is httpOnly, so I can't access it using JS as recommended in the first answer. Is there any documentation out there using httpOnly session cookies in SPAs?

coolboyjules
  • 2,300
  • 4
  • 22
  • 42

2 Answers2

0

You can store the loggedIn state in the cookie,. Use the react-cookie npm package.

constructor() {
    super();
    this.state = {
        loggedIn: false
    }
}

componentWillMount() {
    var loggedIn = cookie.load('loggedIn');
    if(loggedIn !== undefined) {
        this.setState({loggedIn})
    } 
}
logIn = () => {
    this.setState({
        loggedIn: true
    });
    cookie.save('loggedIn', true);
};
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • 1
    But if the cookie is httpOnly, will this still work? Or do I need a new cookie? – coolboyjules Apr 17 '17 at 18:44
  • these cookies will be stored in your brower and hance this will work – Shubham Khatri Apr 17 '17 at 18:48
  • 2
    But I thought you can't read httpOnly cookies from the browser? – coolboyjules Apr 17 '17 at 18:48
  • With react-cookie you have an option to set the httpOnly cookie, however by default it is false and hence the client and read and modify them. I hope it helps. This is an approach I have also used, so I know that this worjs – Shubham Khatri Apr 17 '17 at 18:52
  • 1
    I understand you can create cookies with the flag of httpOnly. But I don't want to create a new cookie. The thing is the server is sending an httpOnly cookie to the browser and saving it because the session management I guess is done on the server. My flask-login knowledge is pretty poor. But I can't touch this cookie anymore. I don't even think you can get it through react. I'm sure there is a common way of doing this I just can't find anything online. – coolboyjules Apr 17 '17 at 19:01
  • This is related: http://stackoverflow.com/questions/42824415/single-page-application-with-httponly-cookie-based-authentication-and-session-ma – coolboyjules Apr 17 '17 at 19:04
0

A possible workaround: I created a /token endpoint. Since the cookie is httpOnly and read by Express (using cookie-parser), I can return it as a response json as provided below.

// An endpoint to get the httpOnly token
// during React app page refresh.
app
    .get('/token', (req, res) => {
        const token = req.cookies.token;
        res.json({ token: token ? token : null });
    });

Now, in React, I can have a useEffect (wherever appropriate, I had it in a provider that wraps components) that calls the above endpoint if a page refresh happens.

useEffect(() => {
    let isSubscribed = true;
    axios.get('/api/token')
        .then((res) => (isSubscribed && res.data.token
            ? setState(token)
            : null))
        .catch((error) => (isSubscribed
            ? console.error(error)
            : null));
    return () => isSubscribed = false;
}, []);

Also refer this article.