Hey everyone, welcome to today’s lecture! Today, we’re exploring cookies—those small pieces of data you’ve likely seen pop up in “accept cookies” banners. Cookies are key to how websites work, from keeping you logged in to remembering your preferences. In this course, we’re working toward authentication (logging in) and authorization (what you’re allowed to do), and cookies are a foundational step for that.
Picture this: You’re using a Blog application. You log in to read posts, or maybe you’re an admin editing them. How does the site remember you as you navigate? Without cookies, every page load would be a fresh start—pretty annoying, right? Cookies fix that by storing info on your device, acting like a memory tag for the site.
Ever wonder why you stay logged in after closing your browser? Or why a site “knows” you when you return? That’s cookies! But here’s a misconception: Some think cookies are just for tracking or ads. Not quite—they’re tools, and their use depends on the developer. Let’s dive in with our Blog application example and build it up step-by-step.
A cookie is a tiny text file a website saves on your device through your browser. It’s like a note the site leaves itself, with a name, a value, and optional settings—like how long it lasts or who can access it.
Here’s a misconception to shake up: People often think cookies hold big personal details, like your email or password. Nope! They usually store simple stuff, like an ID. In our Blog application, when you visit as a guest, it might set:
visitor_id
guest456
That’s super basic—no login yet. We’ll expand this as we go!
Cookies are a collaboration between the browser (client) and server. Here’s the flow:
Set-Cookie
header.In Next.js, we can use the cookies
utility from next/headers
to set and read cookies. Let’s set a cookie server-side for a guest in our Blog application:
// app/api/set-guest/route.js
import { cookies } from 'next/headers';
export async function GET() {
cookies().set('visitor_id', 'guest456', {
path: '/', // Available site-wide
maxAge: 60 * 60, // 1 hour
});
return new Response(JSON.stringify({ message: 'Welcome, guest!' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
When you hit this route, the server sets Set-Cookie: visitor_id=guest456; Max-Age=3600; Path=/
. Your browser stores it, and every request after sends Cookie: visitor_id=guest456
.
Now, on the client side, let’s set a cookie for user preferences (e.g., filtering posts by tag). In a React component:
'use client';
// app/components/SetPrefs.js
import { useEffect } from 'react';
export default function SetPrefs() {
useEffect(() => {
document.cookie = 'prefs=tag:tech; path=/; max-age=86400'; // 1 day
}, []);
return <p>Preferences set to tech posts!</p>;
}
The browser now has prefs=tag:tech
alongside visitor_id
. We’ll handle reading them next.
Cookies need protection—otherwise, they’re vulnerable. A big player here is HttpOnly, which blocks JavaScript from accessing the cookie (e.g., document.cookie
can’t see it). This guards against XSS (Cross-Site Scripting) attacks, where hackers try to steal cookies.
Let’s secure an admin login cookie in Next.js:
// app/api/login/route.js
import { cookies } from 'next/headers';
export async function POST() {
// Imagine we verified username/password
const sessionId = 'abc789xyz';
cookies().set('session_id', sessionId, {
path: '/',
maxAge: 60 * 60, // 1 hour
httpOnly: true, // No JS access
secure: process.env.NODE_ENV === 'production', // HTTPS in prod
sameSite: 'strict', // Blocks CSRF
});
return new Response(JSON.stringify({ message: 'Logged in!' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
Security Features:
session_id
safe from client-side scripts.General Security:
Let’s use cookies in our Blog application. First, server-side, verify an admin session:
// app/api/check-session/route.js
import { cookies } from 'next/headers';
export async function GET() {
const cookieStore = cookies();
const sessionId = cookieStore.get('session_id')?.value;
if (sessionId === 'abc789xyz') { // Check against a DB in real apps
return new Response(JSON.stringify({ message: 'Admin access granted' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
return new Response(JSON.stringify({ message: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
});
}
Now, client-side, read and display the prefs
cookie:
'use client';
// app/components/DisplayPrefs.js
import { useState, useEffect } from 'react';
export default function DisplayPrefs() {
const [prefs, setPrefs] = useState('');
useEffect(() => {
const getCookie = (name) => {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
};
setPrefs(getCookie('prefs') || 'No preferences set');
}, []);
return <p>Your post filter: {prefs}</p>;
}
In action:
session_id=abc789xyz
(HttpOnly, server-only).prefs=tag:tech
→ Client reads it to filter posts.Advantages: Easy to manage state, secure with proper flags. Disadvantages: Small size limit (4KB), can be cleared, needs security care.
Let’s wrap up! Cookies power our Blog application—tracking guests, securing admins, and personalizing views. We set visitor_id
server-side, secured session_id
with HttpOnly, and handled prefs
client-side.
Key Points:
next/headers
in Next.js or document.cookie
on the client.HttpOnly
, Secure
, and SameSite
.Pitfalls to Avoid:
Next time, we’ll build on this for authentication and authorization. Questions? Let’s talk!
Cookies are everywhere online—they keep you logged in, save preferences, and more. Today, we’ll see how they work in our Blog application, setting the stage for authentication!
Some think cookies are just for ads—wrong! They’re tools for functionality, and we’ll prove it. Imagine a Blog app where users read posts and admins edit them. How does it remember you? How does it remember which tabs you opened, or what is your layout in your admin application? Cookies!
Cookies are tiny notes a site leaves in your browser—name, value, and settings like expiration. Simple but powerful!
In our Blog app, a guest gets a cookie: visitor_id=guest456. It’s just an ID, not your life story—surprised? Remember that cookies are sent to server with every request, you want to keep them lean!
Let's check out how to read and write cookies in your server API route or page in NextJS. This API route gets and sets a cookie when a guest visits.
In NextJS we can use the next/headers package that exposes asynchronous value cookies. In non NextJS environment you would use a cookie package.
You can read cookies by name
When you write a cookie, you need to specify to which route in your app this cookie applies, as well as when the cookie expires. The expiration time is in seconds.
On client side, the situation is quite similar. his component sets a cookie client-side to filter posts by tag.
Here, we manually set the value of the prefs cookie setting its value to tag:tech and setting the expiration age. If you want to remove a cookie you simply set the expiration value to a negative number or 0.
Cookies are often the target of malicious attacks. If we store some sensitive information in them, we do not want hackers accessing them, for example, during the XSS attack! There fore cookies have several options that increase their security.
HttpOnly stops JavaScript—like document.cookie—from reading the cookie. In our Blog app, this protects session_id from XSS attacks where hackers inject scripts to steal it.
Secure ensures the cookie is sent only over HTTPS, encrypting it. For session_id, this stops snooping on unsecured Wi-Fi—skip in dev, enforce in production!
SameSite limits when cookies are sent. Strict blocks it from other sites’ requests—like fake forms—preventing CSRF in our admin login.