- Vibe code academy
- Posts
- How you stay logged in a website after only logging in once
How you stay logged in a website after only logging in once
One thing we take for granted when we are using web apps, how come that we have to log in only once and stay “in” every time we open up that website? Does your computer store your login and password and sends them to the web app’s server every time you click a button? Well almost, it’s a bit different and more elegant than that.
Some background context about the tools we are working with and the constraints we have.
Your browser has several places it can store data, one of which is localStorage and the other one is cookieStorage. localStorage is not secure but cookieStorage offers an encrypted way to store key-value pair data.

Now let’s make it clear why we don’t store the login and password in the device. There are two major valid reasons for that
Login and password are authentication methods that are almost permanent to the user for that particular website. For keeping the session active we need a temporary way of authentication that will also be controlled by the web app so that in case of unusual activity can be revoked.
When you store your password in the cookieStorage you potentially expose yourself to be attacked. Yes, cookieStorage is encrypted and more secure than localStorage but that doesn’t mean that it is a good idea to store your password that way. Alternatively you could write your login and password every time you perform an action in that website, but that’s just silly.
Let’s dive into the solution then
JSON Web Token or JWT for short
JWT consists of two tokens, access token and refresh token. These tokens are changing constantly and have expiration dates. Access token is very short lived, something like 15 minutes and refresh token can be valid for weeks or even months. Why two separate tokens you might ask. When interacting with a website, the access token is being used for every action, so you can imagine that it is being exposed quite often throughout your usage session. The access token is stored in the localStorage or even directly in the memory for easy access. That is why the access token is limited to 15 minutes, after that it gets expired and thus not valid. If someone else steals this token they will only have 15 minutes. In order to get a new token after expiration, or in other words refresh your token, you can use the refresh token, hence the name. The refresh token is stored in the cookieStorage. The web app works the following way, you try to access a page and your access token is expired, the website asks you to send the refresh token so that it can refresh your access token and give you the new one.
Let’s look more closely at a JWT, what does it actually look like.

JWT consists of 3 parts separated by dots (the access token that is, the refresh token may or may not look like this, refresh token can be a single string).
Header - indicates the hashing algorithm and the type (usually set to JWT)
Payload - free form data given by the server (can be anything like user_id, created_date etc.)
Signature - a hash of the header + the payload + secret
Secret is a text of random characters, something like 32 characters, that is safely stored in the backend.
Let’s also talk about hashing. Hashing is an algorithm that turns any kind of text into a fixed size seemingly random set of characters. Fixed size means the output text will always have the same size regardless of the input text size, and why seemingly random, because it looks random but every time you input the same text the resulting hashed text will also be the same. Look at these examples
“hello” → “2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824”
“We are learning about JWT and right at this moment we discuss hashing” → “72c22e38e65a2bc36d3cc76ce89133e1543ef91c98e04840438ea1043d103b58”
“Hello” → “185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969”
Notice how “hello” and “Hello” have completely different hashes, even a slight change to the initial text will alter the hash drastically. Now when I run the hashing algorithm on “Hello” the hash will always be the same as here. Try it yourself, find an online SHA256 hashing, input “Hello” and compare. SHA256 is one of the most famous algorithms and there are thousands of them.
With this information in mind we have now the full picture. If we combine the header, the payload and the secret we will get a unique hash. When the server gives this hash to the user no one else can generate a hash that will be valid. When the user sends the token back the server validates the hash by combining the header, the payload and the secret, no one else has access to the secret. Guessing is no option either, if you change even a single character in that secret the hash will change completely and trying all the combinations can take decades.
Recap the user flow
User logs in the website using login and password → the server gives access and refresh tokens to that user → user performs actions in the website with the access token → server checks the validity of the token and the expiration timestamp → access token expires → user uses refresh token to refresh the access token → server validates the refresh toke → server sends the new access token → user continues performing actions with the new access token.
Practical example
Let’s also build a JWT authentication system to better understand how it works. We need two things, a JWT access token verification mechanism on every endpoint that requires user authentication. It will pass on user data if the access token is still valid (not expired) or redirect the user’s frontend to a /refresh endpoint where the server will refresh the user’s access token.
We will build this simple functionality in Snek - Vibe coding for backend. Here is the prompt that goes in to build the JWT validation component.

Here is what the final version looks like. It takes in the JWT and validates if it’s not expired, if it is expired it will give an error so that the frontend will redirect the call to the /refresh endpoint of the server to get a new access token.

And here is what the /refresh endpoint will look like. First the refresh validation component prompt

Now the access token generator component prompt

And here is the final endpoint for access token refresh
