Monday | 15 APR 2024
[ previous ]
[ next ]

Sessions in a Web Application

Date: 2023-04-16

A large part of a website is the ability to log in and log out it. We often times need to be aware of the state of the user and we need information about the user either on the server or in the browser.

This is where sessions come in. One way of doing sessions is to log a user in, generate a token and then save that in a cookie. This cookie is then constantly sent back and forth on each request.

The token in the cookie is then used by the server to check a database for further information. We could just as well look up the username and get the information from the database that way but that could be easily spoofed. We would also have no way of invalidating a username.

This is why we use a randomly generated token. The server can look it up and find the data associated with that current session, if that token isn't there then we can fail the look up and lose nothing.

The logout route would then basically do that. It would erase that session from the database and clear it on the cookie as well. This way future requests won't have the information the server needs to do a look up.

Now that we have an overview of how sessions work, we can talk about 3 places we need to touch to implement our own sessions. I will describe the method for sveltekit specifically but it will be the same everywhere else.

The first step is the /login route. The username and password get posted to the route and you will do all your validation there. Once you have a valid user, generate a token using something like crypto.randomUUID(). Now write this token to a sqlite file along with any data that you want to cache. You don't have to cache anything, saving just the username is fine as well. Now add the token you genearted to the cookies and name it session. This should result in a cookie that will get passed back and forth with the session id. Sveltekit exposes a cookies variable in the routes but all frameworks will have something similar. Worst case, you need to create and write the cookie directly using the request object.

The second step is to change hooks.server.js. This is your server side layer. This chunk of code will run on every request it processes. You will check the incoming cookie for a session, if there is a session then you need to get the data from the database. Now that you have the data, you can add it to the request object that will then flow further to the routes. This is what it means to be middleware. This area is also where you would do any route gating if you need it.

The third step is to then use this session object you tacked into the request object in your routes. In sveltekit, we can load this session data in via the +layout.server.js file. This will then make that data available everywhere through $page variable. Now you can customize the frontend based on session information. The cached data from above is availble or you can use just the username to fetch more information from the database. Make sure any cached data isn't sensitive as it will be sent to the browser.

The final step of sessions is to log the user out. You can write a logout endpoint that will clear the cookie you created in the login route and you can delete the session data from the database.

Overall sessions are a very simple thing to implement but it does require bouncing around in multiple files to get everything working. I really wish there was a simple set and forget option for authentication using your own username and passwords. Some of the auth libraries that use 3rd party authentication look great but it's not often that I have a universal 3rd party.