Transcript
  • Web

Session Identifiers

From the class:  Session Cookies

The purpose of Session is to be able to uniquely identify a user by some kind of ID so that we can retrieve information about that user over many, many requests, and potentially over many, many browser sessions. Right now our app session cookie is just set to this string. And what we want to do is to set it to an identifier that will identify our user. When the user sends a future HTTP request, they can pass up that identifier and we can retrieve it.

So let's create a function called getSession where we can put this logic. And again, it will take the request object. This method is going to add a property to the request called Session. And that's either going to be equal to a session that already exists from the header from the cookie, or one that we'll create from scratch right now.

So we'll look at the cookies that were added to the request object up here. And we'll look for the one called AppSession. And if that exists, then we'll just go ahead and use it. Otherwise, we'll create a new variable to put in-- or a new value that we'll put in this Session property. And the value will be a random identifier that we'll create.

So to do that node, I can use the Crypto module. And there's a method called randomBytes. And we pass it how many bytes we want to use or how many random bytes we want. And then I'm going to convert it to a string in hexadecimal format so we can send it over the wire. So if we already have a session identifier, we'll just use it directly. Otherwise, we'll create a new one.

Down in our application, we'll call the getSession method passing the request just like we did above. And now in the Set-Cookie header, let's change this from some value to actually be the variable of the session that we set in the request. I use a special string, JavaScript string syntax here to use variables inside of the string. And we're going to set the AppSession equal to the value of request.session. Now when I make a GET request to the server using cURL, notice the cookie app session is set to this identifier.

You can imagine that the server could use this identifier to query a database and say, give me back all the information you have for this ID. Or it might query a cache server, like memcached and say, pull back the user information for anything associated with this ID. If I make additional requests using cURL, I get a new ID each time. And that's because I'm not sending the ID back to the server, so it thinks it's a brand new session and it creates a new session ID. But if we head to the browser, which will automatically send this cookie back up to the server, you'll see that the ID remains the same.

We can start off with a blank slate by clearing any cookies that exist already. I'll right-click on the cookies localhost domain and select the Clear option. Then when I refresh the browser, we get an AppSession cookie with a value set to a unique identifier. But this time, if we refresh the browser, unlike in cURL, I keep the same ID. And that's because their browser is sending up the cookie as a header to the server, so the server sees that we already have a session and it doesn't create a new one.

To see that header, we can click on the Network tab and then look at the request that the server made and scroll down to the bottom of request headers, see the cookie header that it's set. And the value for that cookie header has the identifier that we got from the server. So each request, the browser will send this AppSession up to the server and the server will be able to identify us using this ID.

There's one problem with this implementation. Notice back in the Resources section in the Cookies area the Expires, Max Age for this cookie is set to Session. What this means is that when we close this browser, the browser considers this session to be complete and it will delete this cookie for us automatically. If you want this cookie to last beyond just this one browser session, we need to set a special property on it that tells it to expire at some later time. And so we'll either set a max age or an expire date.

Let's go back to our code and implement that. If I add a semicolon after the AppSession key, there's a special key I can use called Expires. And the browser will treat that specially. It will tell the browser to keep the cookie around until this particular Expires date. So I'll set this equal to a variable called expires, which we'll set.

And I'm going to set it to expire one year from now. You could set it to be whatever value you want. I'm going to create a helper function called oneYearFromNow, which will return a date that is one year from now, and then call a special method on that to get it into GMT time. So to do that, I can say toGMTString. This will convert the date to Greenwich Mean Time, so that's going to be England time. And so you can use whatever libraries are available to you in your language to get this in the right format.

Let's go ahead and create that function. I'm just going to paste it in to save some time. And this is just because the JavaScript syntax for creating these dates is very bizarre. So I'm going to create a new date, set its year to be one year from now, and just return it.

Let's head back to the browser and make sure that it's picked up this new expires key. After I refresh, we now have a value in the Expires field here. So we can close this browser and open it up again and refresh as many times as we want and the AppSession ID will stay the same instead of being deleted because the cookie going away.

While we're thinking about it, I'd like to set two more properties on the cookie. The first one is this HTTP value here. Notice that it's blank. That means that we can access this cookie through JavaScript just by typing document.cookie, and it comes back in string form. And we can even mutate it or change it right here in the browser.

This is a bit of a security risk, because if you get somebody else's JavaScript somehow executing on your page, they can grab this cookie from the document and maybe even send it to some other server. So that's generally not a good thing, so we're going to set a special property that disables that behavior.

The other thing I want to set back in the server is the path. Right now it's being set automatically for us, but let's be more explicit. The path says which path of the application should this cookie apply to. And we want to set it to the root path so that it applies for the entire app.

I can add these extra properties just by putting a semicolon at the end. I'll set the path first. And then we can use a special option called HttpOnly. And we don't need to put a semicolon at the end there. This will tell the browser that the path is the root path and the cookie should be HTTP only, which means the cookie should only be accessible when it's being transported over HTTP, not by JavaScript.

Now when I refresh the browser, notice the HTTP box has a checkmark in it, which is a good sign. And if we come down into the console area and I type document.cookie, I can't even see it. It's just blank.

Another security-related property that you've probably seen over here is called secure. You might be wondering what that is and why it's blank. That tells the browser that this cookie should only be transmitted if we're on a secure connection, on HTTPS, and not over regular HTTP. I'm not going to set that for now. We're just going to leave it so that we can send the cookie over regular HTTP connections. But you can set that if you want by setting this Secure option. And that will tell the browser to only send it if we have a secure connection, only send the cookie on secure connections.

OK. So we've got everything set up now for our cookie, our AppSession with a unique session ID to be transmitted with each request and to last beyond just this one browser session.