LiteNode's logo

LiteNode

Docs GitHub logo
▶ Usage

Documentation

Cookie Management in LiteNode

LiteNode now includes a comprehensive cookie management system that makes it easy to set, read, and manage cookies in your web applications. This document covers how to use the cookie management features and best practices for working with cookies.

To work with incoming cookies, you first need to enable the cookie parser middleware:

const app = new LiteNode()

// Enable cookie parsing
app.enableCookieParser()

After enabling the cookie parser, all incoming requests will have a cookies object containing parsed cookie values.

Setting Cookies

You can set cookies using the setCookie method on the response object:

app.get("/welcome", (req, res) => {
    // Set a simple cookie that expires when the browser is closed
    res.setCookie("greeting", "Hello there!")

    res.txt("Welcome to our site!")
})

You can pass various options when setting cookies:

res.setCookie("preferences", "dark-mode", {
    maxAge: 30 * 24 * 60 * 60, // 30 days in seconds
    path: "/",
    httpOnly: true,
    secure: true,
    sameSite: "Strict",
})

Available options:

Option Type Description
maxAge number Maximum age of the cookie in seconds
expires Date | string Specific expiration date
path string Path where the cookie is valid (defaults to '/')
domain string Domain where the cookie is valid
secure boolean Whether the cookie should only be sent over HTTPS
httpOnly boolean Whether the cookie should be inaccessible to JavaScript
sameSite string CSRF protection: 'Strict', 'Lax', or 'None'

Reading Cookies

Once cookie parsing is enabled, you can access cookies from the request object:

app.get("/dashboard", (req, res) => {
    const theme = req.cookies.theme || "light"
    const username = req.cookies.username || "Guest"

    res.render("dashboard", { theme, username })
})

Clearing Cookies

To remove a cookie, use the clearCookie method:

app.get("/logout", (req, res) => {
    res.clearCookie("username")
    res.clearCookie("auth_token")

    res.redirect("/login")
})

If you set the cookie with specific options like path or domain, you need to include the same options when clearing:

// Clear a cookie with a specific path
res.clearCookie("tracking", { path: "/products" })

// Clear a cookie set for a specific domain
res.clearCookie("preferences", { domain: "shop.example.com" })

Working with Signed Cookies

Signed cookies add an extra layer of security by ensuring that the cookie hasn't been tampered with. To use signed cookies, first create a signed cookie utility:

const app = new LiteNode()
app.enableCookieParser()

// Create a signed cookie utility with a strong secret
const signedCookies = app.createSignedCookies("your-secure-secret-key-at-least-16-chars-long")

Setting Signed Cookies

Use the signed cookie utility to set cookies that are cryptographically signed:

app.post("/login", async (req, res) => {
    // Authenticate user (not shown)
    const userId = "12345"

    // Set a signed cookie
    await signedCookies.setCookie(res, "userId", userId, {
        maxAge: 24 * 60 * 60, // 1 day
        httpOnly: true,
        secure: true,
    })

    res.redirect("/dashboard")
})

Reading and Verifying Signed Cookies

To verify signed cookies:

app.get("/profile", async (req, res) => {
    // Get and verify the signed cookie
    const userId = await signedCookies.getCookie(req, "userId")

    if (!userId) {
        // Cookie was invalid or tampered with
        return res.redirect("/login")
    }

    // Continue with the verified userId
    const userData = await getUserData(userId)
    res.render("profile", userData)
})

Security Best Practices

  1. Always use httpOnly for sensitive cookies to prevent access from JavaScript (protects against XSS attacks)

  2. Set secure: true in production to ensure cookies are only sent over HTTPS

  3. Use sameSite: 'Strict' or 'Lax' to protect against CSRF attacks

  4. Use signed cookies for any cookie data that needs integrity protection

  5. Keep cookie data minimal - store only what you need (like session IDs, not entire user objects)

  6. Set appropriate expirations - use the shortest practical lifetime for your cookies

  7. Use specific paths when applicable to limit cookie scope

API Reference

Response Methods

res.setCookie(name, value, options)

Sets a cookie with the given name, value, and options.

See Setting Cookies section.

res.getCookies()

Gets all cookies set on the response.

app.get("/checkout", (req, res) => {
    // Set multiple cookies
    res.setCookie("cartId", "12345")
    res.setCookie("tracking", "checkout-flow")

    // Get all cookies that have been set on this response
    const cookies = res.getCookies()
    console.log("Cookies set:", cookies)
    // Output: Cookies set: ['cartId=12345; Path=/', 'tracking=checkout-flow; Path=/']

    res.render("checkout")
})

res.clearCookie(name, options)

Clears a cookie by setting its expiration in the past.

See Clearing Cookies section.

LiteNode Methods

app.enableCookieParser()

Enables cookie parsing middleware.

See Enabling Cookie Parsing section.

app.createSignedCookies(secret)

Creates utilities for working with signed cookies.

See Working with Signed Cookies section.

Request Properties

req.cookies

Object containing all cookies sent by the client, with cookie names as keys and values as strings.

Examples

import { LiteNode } from "litenode"
const app = new LiteNode()

app.enableCookieParser()

// Set a cookie on one route
app.get("/set-language", (req, res) => {
    const lang = req.queryParams.get("lang") || "en"
    res.setCookie("language", lang, { maxAge: 365 * 24 * 60 * 60 }) // 1 year
    res.redirect("/")
})

// Read the cookie on another route
app.get("/", (req, res) => {
    const language = req.cookies.language || "en"
    res.render("home", { language })
})

app.startServer(3000)

Authentication Example with Signed Cookies

import { LiteNode } from "litenode"
const app = new LiteNode()

app.enableCookieParser()
const signedCookies = app.createSignedCookies("my-secure-secret-key-change-me")

// Mock user database
const users = {
    user1: { password: "pass1", name: "Alice" },
    user2: { password: "pass2", name: "Bob" },
}

// Login route
app.post("/login", async (req, res) => {
    const { username, password } = req.body

    // Basic authentication
    if (users[username] && users[username].password === password) {
        // Set a signed session cookie
        await signedCookies.setCookie(res, "session", username, {
            maxAge: 3600, // 1 hour
            httpOnly: true,
            secure: process.env.NODE_ENV === "production",
            sameSite: "Lax",
        })

        return res.redirect("/dashboard")
    }

    res.status(401).txt("Invalid credentials")
})

// Protected route with authentication check
app.get("/dashboard", async (req, res) => {
    const username = await signedCookies.getCookie(req, "session")

    if (!username || !users[username]) {
        return res.redirect("/login")
    }

    const user = users[username]
    res.render("dashboard", { name: user.name })
})

// Logout route
app.get("/logout", (req, res) => {
    res.clearCookie("session")
    res.redirect("/login")
})

app.startServer(3000)

User Preferences Example

import { LiteNode } from "litenode"
const app = new LiteNode()

app.enableCookieParser()

// Save user preferences in a cookie
app.post("/save-preferences", (req, res) => {
    const { theme, fontSize, notifications } = req.body

    // Create a JSON string of preferences
    const preferences = JSON.stringify({
        theme: theme || "light",
        fontSize: fontSize || "medium",
        notifications: notifications === "on",
    })

    // Save preferences in a cookie that lasts 1 year
    res.setCookie("userPrefs", preferences, {
        maxAge: 365 * 24 * 60 * 60,
        path: "/",
    })

    res.redirect("/settings?saved=true")
})

// Apply preferences to all pages
app.use((req, res) => {
    // Default preferences
    let userPrefs = {
        theme: "light",
        fontSize: "medium",
        notifications: true,
    }

    // Try to get preferences from cookie
    if (req.cookies.userPrefs) {
        try {
            userPrefs = JSON.parse(req.cookies.userPrefs)
        } catch (e) {
            // Invalid JSON, stick with defaults
        }
    }

    // Add preferences to req object for use in route handlers
    req.userPreferences = userPrefs
})

app.get("/settings", (req, res) => {
    const saved = req.queryParams.get("saved") === "true"
    res.render("settings", {
        preferences: req.userPreferences,
        saved,
    })
})

app.startServer(3000)

By following the best practices and using the cookie management features provided by LiteNode, you can create secure and efficient web applications that properly handle client state through cookies.

Content