Cookie-Based Authentication: A Simple Guide for Secure Sessions
Straightforward guide to implementing secure cookie-based authentication with proper session management.

What is Authentication? Authentication is the process of verifying the identity of a user, device, or entity in a system. It ensures that the person or system accessing resources is who they claim to be. The main goal of authentication is to protect systems and data from unauthorized access.
Simple enough, yes but let’s focus on the how rather than the why in this blog. We can do authentication in multiple ways, especially with so many libraries that are prevalent today, like Next-Auth, Clerk, Lucia, AuthO, Passport, etc. But let’s focus on 2 custom authentication systems for now, that we can make use of, one is JWT + Local Storage and the other being Cookies.
JWT + Local Storage
Now, what is JWT, JWT or JsonWebToken is a way to transmit information between parties as a JSON object, This information can be verified and trusted because it is digitally signed. It contains a header, payload and a signature containing various aspects of the information we want to transmit safely.
Here is an example of JWT:-
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cplain text
Now, JsonWebTokens can be used for various use cases like access control, user authentication, secure data transmission, etc. but let’s just focus on the authentication aspects of it for this blog.
Coming onto localStorage, localStorage is a web storage feature allowing web application to store data on the browser with no expiration time, which means data is persisted even after browser is closed and reopened until it is cleared manually. It provides a synchronous API to interact with through Javascript code. It can be used to store user preferences, caching data for offline use, authentication tokens, form data to save it temporarily in case the user navigates away from the tab and more such use cases.
In a client side application, what we usually do in a case where local storage is to be used for authentication is, storing the token we recieve upon signing in/signing up in the localStorage to be utilised later whenever sending a request on the protected routes by setting the token in the headers of that request.
Too verbose? Basically something like this
axios.get('https://xyz.com/api/dummy', { headers: { Authorization: localStorage.getItem('token')}}plain text
Now, this is a good enough way to do authentication, simple and straight forward, then why do we require another way like cookies to do authentication if this works must be the question, there is a problem with this approach, and that is known as Cross Site Scripting(XSS).
Cross Site scripting is a type of security vulnerability in web applications, which occur when a malicious user injects script on web pages viewed by other users, these scripts are then executed in the context of victim’s browser, which can potentially allow the malicious attacker to access sensitive information like authentication tokens, session tokens, deface websites or even hijack user sessions.
Imagine a cross site scripting attack intended to steal your user’s authentication token, if stored in the localStorage, a user’s information can easily be stolen from the localStorage as it presents an entire synchronous API to interact with by just doing a simple
localStorage.getItem('token')plain text
You don’t want this to happen, so you must come up with ways to mitigate this potential threat. One such way is to use cookies for transmitting authentication tokens.
Cookies
Cookies are small pieces of data stored on user’s web browser while the user is browsing sent by the website, they provide a reliable mechanism for websites to store multiple things like user preferences, authentication cookies and more.
They are generally used for session management, personalization, tracking across websites and security. The focus of the blog is related to it’s security related applications, so let’s take a deep dive on cookie based authentication.
We know and have discussed one potential reason as to why we prefer cookies over localStorage above, that is Cross Site Scripting(XSS), but there are other possible reasons for using Cookies too, like the following:-
- Automatic Inclusion: Cookies are sent with every subsequent request once they are set on the client side and you don’t have to explicitly set a header for every API call.
- Server Side Rendering Compatibility: Local Storage doesn’t work with NextJs without compromising on a lot of offerings it gives you, because localStorage is a client side synchronous API whereas NextJs components are pre rendered on the server side by default, so cookies become super important in NextJs.
- Security Features: Cookies have an expiry set to them and can be restricted to only https transmission and certain domains.
Types of Cookies
There are two main types of Cookies we need to look at:-
- Persistent - These are cookies that stay on your browser even if you close the window, as they are used, as the name suggests to be “persisted” across multiple user sessions. They only expire when they reach their expiry time/date or the user manually deletes them.
- Session - These are cookies that stay on your browser for the duration of a session, and get removed automatically once a user session finishes.
Properties of Cookies
Cookies have multiple properties which can be used for multiple cases, such as:-
- Secure: Ensures that cookies is sent only over https connection, which is a secure and encrypted connections.
- HttpOnly: This ensures that cookies aren’t accessed by client side scripts, mitigating Cross Site Scripting attacks.
- Expires and Max-Age: Specifies the expiration date and maximum age of the cookies(in seconds) respectively after which the cookie is deleted.
- Domains and Path: Specifies the domain and the path within the domain for which the cookie is valid respectively.
- SameSite: Controls whether cookies are sent with cross-site requests, helping to prevent CSRF attacks. There are three settings for the SameSite attribute
— Strict: Cookies are only sent in a first-party context, meaning they are only sent if the request originates from the same site as the target URL. This prevents cookies from being sent with requests from third-party sites, effectively blocking CSRF attacks but also potentially breaking legitimate cross-origin use cases.
— None: Cookies are sent with all requests, including cross-origin requests. This is the default behavior if the SameSite attribute is not set, but for None to work, the Secure attribute must also be set.
— Lax: Cookies are sent with top-level navigation requests and some GET requests (e.g., when a user clicks a link to the site) but not with embedded requests like images or frames from third-party sites and POST requests which actually allows a malicious user to potentially affect the database. This provides a balance between security and usability, preventing most CSRF attacks while allowing some cross-site requests.
I have mentioned this term CSRF attacks a few times now, so let’s understand what it means.
CSRF Attacks
A CSRF attack occurs when an attacker tricks a user’s browser into making an unwanted request to a different site at which the user is authenticated. This can happen because browsers automatically include cookies with every request to the server they are associated with.
For example:-
- A user is logged into their bank website and has an active session cookie.
- The user visits a malicious site while still logged into the bank website.
- The malicious site contains a form that automatically submits a request to the bank’s transfer funds endpoint, exploiting the user’s active session.
- The bank server processes the request because it is sent with the user’s session cookie, leading to an unauthorized transfer of funds.
Conclusion
While both JWT with local storage and cookie-based authentication provide methods for maintaining secure sessions, cookies offer a more secure alternative, particularly against Cross-Site Scripting (XSS) attacks. By leveraging properties such as HttpOnly, Secure, and SameSite, cookies mitigate common vulnerabilities and integrate seamlessly with server-side rendering frameworks like Next.js. Choosing cookies for authentication can enhance the security of your web applications, protecting sensitive user information and ensuring robust session management. Adopting the right authentication strategy tailored to your specific needs is crucial for maintaining the integrity and security of your systems.