This is how user authentication typically works:
First, the user will fill out a form, providing the necessary credentials. The credentials will be transferred to a controller in the backend.
The controller will try to match the credentials to the ones stored in the database. If the match is successful, the user is successfully authenticated. In this case, the controller will send a piece of user information back to the frontend, which will be stored inside the browser.
As long as this information exists, the user is considered authenticated and will not be required to provide credentials again.
So, before we can talk about how to create a user authentication system, you must first understand how to store a piece of data inside the user's browser, and that's what we are going to cover in this lesson.
Cookies
There are mainly four ways to store data in the browser: cookies, localStorage
, sessionStorage
, and IndexedDB.
A cookie is a small piece of string data stored in the user's browser. It is primarily used for user authentication and personalization. You can set a cookie using the document.cookie
setter like this:
1document.cookie = "<name>=<value>";
The cookie name is unique. If you set multiple cookies with the same name, only the latest one will be preserved.
1document.cookie = "user=John";
2document.cookie = "user=Doe";
3
4console.log(document.cookie);
1user=Doe
Reminder: We are now working in the browser environment, so run the above code demo in the JavaScript Console.
Setting expiration date
Besides the name, you can also set attributes for the cookie.
1document.cookie = "<name>=<value>; <attribute>=<value>";
For example, if you want the cookie to expire at a certain time, you can set an expires
attribute.
1document.cookie = "user=John; expires=Tue, 19 Jan 2038 03:14:07 GMT";
The date must be set in this exact format, so it is best to use the date.toUTCString()
method.
1const date = new Date("2025-08-25T12:10:26+06:00");
2
3let expires = "expires=" + expirationDate.toUTCString();
4document.cookie = "user=John; " + expires;
Alternatively, you could use the' max-age' attribute to specify how long you want the cookie to be valid instead of setting an expiration date directly.
1document.cookie = "user=John; max-age=3600";
In this case, the cookie will be valid for 1 hour (3600 seconds).
Of course, there are other attributes you could set depending one your specific use case. You can find a full list of cookie attributes here.
Reading cookies
However, there is another question: how do we read from a cookie? Besides the document.cookie
getter and setter, there are no built-in functions that allow you to work with cookies.
But remember, a cookie is just a string that follows a specific format, which means you could extract data from it using the regular expressions we discussed previously. Consider this example:
1document.cookie = "theme=dark";
2document.cookie = "number=42";
3document.cookie = "status=active";
4
5console.log(document.cookie);
1number=42; status=active; theme=dark;
Three cookies, theme
, number
, and status
, are set for this specific web application. As you can see, the document.cookie
getter will combine all three of them together.
You can create a helper function to retrieve an individual cookie.
1function getCookie(name) {
2 let regex = new RegExp("(^|; )" + encodeURIComponent(name) + "=([^;]*)");
3 let match = document.cookie.match(regex);
4 return match ? decodeURIComponent(match[2]) : null;
5}
6
7let theme = getCookie("theme");
8let number = getCookie("number");
9let status = getCookie("status");
10
11console.log(theme); // -> "dark"
12console.log(number); // -> "42"
13console.log(status); // -> "active"
Cookies are also accessible from both the client side and server side, which makes it perfect for verifying if a user is authenticated. We will talk more about accessing cookies on the server side later.
localStorage and sessionStorage
A cookie is typically around 4KB, which is not very much. If your application requires more storage, consider using localStorage
instead, which allows for 5MB per domain.
Data inside localStorage
will be stored in key/value pairs, which can be set using the setItem()
method.
1localStorage.setItem("username", "JohnDoe");
And getItem()
retrieves a stored item:
1localStorage.getItem("username");
1JohnDoe
Items stored in the localStorage
can only be accessed from the client side.
sessionStorage
works just like localStorage
, except it stores temporary data. Once the browser page is closed, or in technical terms, when the session is over, the stored data will be lost.
1sessionStorage.setItem("username", "JohnDoe");
2
3sessionStorage.getItem("username");
1JohnDoe
And just like localStorage
, sessionStorage
is only accessible from the client side.
IndexedDB
IndexedDB is a fully featured database built into the browser. In most case, you don't need this kind of power. It is designed for web apps that needs to run offline.
It is impossible to cover everything about this database in one lesson, and frankly, it possesses too much power for this course. So, instead of discussing it in detail, we are only going to give one example below.
1// Open the database myDatabase with version number 1. A new database will be created if myDatabase does not exist
2let request = indexedDB.open("myDatabase", 1);
3
4// This event is triggered if the database needs to be upgraded, meaning when the database is created for the first time or if a new version is requested
5request.onupgradeneeded = function (event) {
6 let db = event.target.result;
7 let objectStore = db.createObjectStore("users", { keyPath: "id" });
8 objectStore.createIndex("username", "username", { unique: true });
9};
10
11// This event is triggered when the database is successfully opened
12request.onsuccess = function (event) {
13 let db = event.target.result;
14 let transaction = db.transaction(["users"], "readwrite");
15 let objectStore = transaction.objectStore("users");
16 let user = { id: 1, username: "JohnDoe" };
17 objectStore.add(user);
18};
If you are interested, check out the complete API of IndexedDB for more details.
Summary
Feature | Cookies | LocalStorage | SessionStorage | IndexedDB |
Purpose | Session management, personalization, tracking | Storing user preferences, application state | Temporary storage for a single session | Storing large amounts of structured data |
Capacity | ~4KB per cookie | ~5MB per domain | ~5MB per domain | Hundreds of MBs per domain |
Accessibility | Client and server-side | Client-side only | Client-side only | Client-side only |
Persistence | Configurable expiration | Persistent until explicitly deleted | Duration of the page session (tab/window) | Persistent until explicitly deleted |
Security | Can use HttpOnly and Secure flags | Vulnerable to XSS | Vulnerable to XSS | Vulnerable to XSS |
Scope | Shared across all tabs/windows | Shared across all tabs/windows | Unique to each tab/window | Shared across all tabs/windows |