Automatically Checking if a User is Logged In in React
Now that we have a working solution for our authentication tool, let's address one of the key bugs.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

, If I open up another browser window in incognito mode just to make sure we don't have any issues with any leftover cookies or anything like that, I'm gonna go to localhost:3000 you can see that it has our state as NOT_LOGGED_IN, that's what we'd expect for a new session.

But now if I log in here, then you will see that after I've logged in, it updates the state so we're LOGGED_IN, so that's what we'd expect but now if I hit Refresh, then it has switched back to NOT_LOGGED_IN and that is a bug. We want the ability to maintain the state and to check with the server to see if we are authenticated or not.

It would be a very bad user experience if we had to log in every time we came to the application, so I'm going to get out of this, open up a new incognito mode window again just so we can start with a fresh session and now let's implement exactly what we need.

So, the process that's gonna take place is there is an endpoint on DevCamp Space called LOGGED_IN and what we can do is check that endpoint to see exactly what the current state of the logged-in status is. It'll simply tell us that yes, we're logged in or no, we're not, so let's start building that out.

So, I'm gonna open up Visual Studio Code. Now, this is gonna come inside of the app.js component and I'm going to add a couple of methods here. The very first one is going to be one that let's just call it checkLoginStatus. It's not gonna take any arguments and then inside of here, we are going to call Axios.

Now, we have not imported Axios inside of this component yet, so make sure that you do that at the top, so I'll say import Axios from Axios and then down in the method here, what I wanna do is make sure that we are returning a value here, so I'm gonna say return Axios and then the argument here is going to be, or I should say the method here is gonna be a get request.

So I'm just gonna say axios.get and then inside of here, I'm going to type in the endpoint, so the endpoint we're gonna use here is https://api.devcamp.space/logged_in and so that is the argument that we're passing in. Now the second argument, and this one is absolutely critical, if you don't have this then it's not going to work, is passed in as an object withCredentials: true, just like this and I'll remove the IntelliSense, just so you can see it.

So the full line that we're gonna have here is return axios.get, so we're making a get request, we're passing in the API link which is api.devcamp.space/logged_in comma and then follow that with the withCredentials: true wrapped inside of an object, so that's the very first thing that we need to do.

app.js

checkLoginStatus() {
  return axios.get("https://api.devcamp.space/logged_in", { withCredentials: true })
}

Now, after we've done this, what we're going to do is because remember that Axios returns a promise, so with any promise we need to call then on, so I'm gonna hit save so it formats it for us and so, let me get rid of the semicolon and type then, and for right now we're going to grab the response and then pass it an arrow function and for right now let's just see what kind of data we have to work with.

So I'm gonna console.log, this is gonna be from the logged_in return and then let's just see what data that it brings us back, so I'm gonna say response here and then how do we call this checkLoginStatus? I think this is something we could use the lifecycle hooks for, so we can use componentDidMount and then simply call checkLoginStatus, so this.checkLoginStatus, hit save and now we should get a console.log.

So if I come here, I'm not sure if this is gonna work in incognito mode 'cause I'm not sure the status of the session and the cookie, so let me open up a new browser window and go to localhost:3000 and let's open up the browser dev tools.

So, right here you can see that this printed out, so we know that our function ran and it says logged_in returns this object and it has a data parameter here and we can see that it returns logged_in false.

large

So this is good because we are not logged in right now, this is exactly what we would hope to see, so that is good so far. Now let's come to the auth page and let's Login, and you can see we're still getting this same value back, logged_in is now still logged_in: false, so everything's still good there.

Now let's type in whatever your email and password are to DevCamp Space, hit Login, and now you can see that we're logged_in. Now, nothing got printed out because we don't need anything to get printed out yet because the state has already been updated.

What we're trying to implement should be, its sole purpose should be for when you or a user comes back to the site, so we could mimic that by just coming to a new tab, you could also just hit Refresh and then let's see what we have. So, now we get logged_in and it returns this object.

Now you can see it returns logged_in, data is now true. So, that is perfect, that's exactly what we're looking for and if you open it up, you can see that you'll even have access to all of your data such as your email address, ID, this is not my password, it's a hashed password, so this does no one any good, it's fully encrypted, it has my subdomain, all kinds of different data points that I might need.

So now we know that we're logged in, so we're pretty much halfway there. Now that we have all of this data, what we can do, we can build a conditional inside of the code, inside of that function. So, right here with our then response, instead of just console logging this, what I'm gonna do is I'm going to grab the variables, I'm gonna grab the data, store them in variables and then I'm gonna implement a conditional.

So I'm gonna say const and I'll just say loggedIn, and I'll use camelCase, equals and then response.data.logged_in. So, all I'm doing, and the reason why I'm doing this is because our conditional's gonna have about I think three different conditions, we're gonna have to check for and I do not wanna have to type this every single time.

I don't wanna say if response.data.logged_in is equal to this, I want you to perform one task. That is just gonna get very cumbersome and it's gonna make the whole conditional pretty tough, so now I can just say if loggedIn and that will give me the same data, and let's also do that for state, just to make it easier.

So I'll say const and then loggedInStatus equals this.state.loggedInStatus and now it's gonna give us some code that's a little bit easier and more manageable to work with. So, as a comment, let's just type out what we're looking to do with the conditional.

So, the first condition needs to check, so I'm gonna say if we're loggedIn, so this is our response, so I don't want you to get these two things confused, this is the response coming back from the API call, this is whatever state is.

So I'm gonna say if we're loggedIn and the status is LOGGED_IN just like this, then we don't really need to do anything 'cause what that's telling us is yes, we got confirmation that we're logged in and also we already had it in state, so we don't have to make any changes. In this case, we can just return the data, something like that, we don't have to make any updates or anything like that.

Now, another condition though, so we're gonna say if loggedIn, so in other words, if the response is true, and we can say if loggedIn and then from there say okay, well, what happens in the second case? So, what happens if the status in our state is not loggedIn? Well, in that case, we need to update the state and tell it that we want to change it to LOGGED_IN, so that will update the state for us.

Now, that's the second condition and now we'll say okay, well, that worked but now what happens if not loggedIn, so in others words, if we call this API and it says no, you are not loggedIn and then the status is LOGGED_IN, then we want to make sure that we log out, so update state and make it so it is logged out.

So, I think that that takes care of all of the scenarios and so, if not, we'll find it later on but this should take care of each of the different things that we wanna cover. I'll keep the comment here for now as I'm writing out the code, so I'll scroll up and now let's start writing it.

So I'll say if loggedIn, and loggedInStatus is equal to LOGGED_IN, in that case, I don't wanna do anything, remember, we just want to return the data, so here we can just return loggedIn and it's not gonna do anything, so there are no issues with that. Maybe some time later on, we might wanna add a little notification, anything like that, at least we'll have access to that condition and the other nice thing, the reason why I'm putting this at the top is because if this is true, nothing else in the conditional's gonna be checked, so this is good for performance as well.

So, the next condition, so I'll say now else if, this is gonna be this second condition here, so I'll say else if loggedIn and loggedInStatus is triple equals NOT_LOGGED_IN, then we want to update the state, so now we wanna update state to change it to LOGGED_IN, so I can say here this.setState and inside of here we can just say loggedInStatus is updated to LOGGED_IN and that is all that we need to do there.

Now, the third condition, so right here, if we get back a response of NOT_LOGGED_IN but the status is loggedIn, then we also need to update the state. So, in that case, because it's very similar, let me just copy this, so now we'll say else if and just change this to say NOT_LOGGED_IN which we can accomplish by putting the bang, remember, anytime you put the exclamation mark, also called a bang, right in front of a Boolean value, it checks for the opposite.

So this is the same thing as saying if loggedIn is triple equals set to false, that's what we're looking for but this is a much cleaner way of writing it, so I'm gonna say if not loggedIn, and loggedInStatus is set to LOGGED_IN, then we need to update the status to say NOT_LOGGED_IN.

Okay, and then just to be on the safe side, anytime that you have any type of promise like this with an API, make sure at the very end of it let's also add a catch, so I'll say catch any errors that come through. These are just server-side errors. This isn't gonna be an authentication thing, this is just checking to see maybe the API is down, anything like that, so now we'll console.log Error and make sure we print out the actual error itself.

Okay, I believe that this is everything, so let's try this out and see if it's working. So, I'm gonna switch back to Chrome, you can see we're logged in, you can click around here, everything looks like it's working. Now if I hit Refresh, you can see it said NOT_LOGGED_IN there for a second, that's how long it took it to call the API and then it automatically updated to LOGGED_IN.

So that is working perfectly, this is exactly the behavior that we wanted. If you go to the site tomorrow or anything like that, you should get this exact behavior, so that is working really nicely.

Now let's test out the negative case. So, let's open up, close out all your incognito windows, and test it out. Localhost:3000, we are NOT_LOGGED_IN, so it was able to check to see it called the API, it said are they logged in? No, okay, so make sure updated state stays like this, so everything now is working very nicely.

In the next guide, I wanna show you how we can now update the routes so that we can show and hide navigation links that only authorized users should be able to access along with completely removing the route definitions.

Resources