Vix.cpp v2.6.0 is here Read the blog
Skip to content

Cookies

This example shows how to read and write HTTP cookies with Vix.

Use cookies when you need to store small client-side values such as:

txt
theme preference
language preference
visitor id
CSRF token
small browser state
session id

For server-side session data, use the session middleware.

For authentication, prefer signed sessions, JWT, or another explicit auth strategy.

What this example builds

The app exposes:

txt
GET /cookie/set
GET /cookie/read
GET /cookie/delete
GET /theme/light
GET /theme/dark
GET /theme

It demonstrates:

txt
setting a cookie
reading a cookie
deleting a cookie
using cookie options
reading cookies from Request
writing Set-Cookie to Response

Use:

cpp
#include <vix/middleware.hpp>

or include only the cookie helper:

cpp
#include <vix/middleware/http/cookies.hpp>

The cookie helpers live in:

cpp
vix::middleware::cookies

Project structure

Create:

txt
cookies_demo/
└── cookies.cpp

Create the file:

bash
mkdir cookies_demo
cd cookies_demo
touch cookies.cpp

Source

Open:

txt
cookies.cpp

Add:

cpp
#include <string>

#include <vix.hpp>
#include <vix/middleware.hpp>

using namespace vix;

static void install_middleware(App &app)
{
  app.use("/cookie", middleware::app::request_id_dev());
  app.use("/cookie", middleware::app::timing_dev());
  app.use("/cookie", middleware::app::security_headers_dev());

  app.use("/theme", middleware::app::request_id_dev());
  app.use("/theme", middleware::app::timing_dev());
  app.use("/theme", middleware::app::security_headers_dev());
}

static void set_cookie(
  Response &res,
  std::string name,
  std::string value,
  int max_age)
{
  middleware::cookies::Cookie cookie;

  cookie.name = std::move(name);
  cookie.value = std::move(value);
  cookie.path = "/";
  cookie.max_age = max_age;
  cookie.http_only = true;
  cookie.secure = false;
  cookie.same_site = "Lax";

  middleware::cookies::set(res, cookie);
}

static void delete_cookie(
  Response &res,
  std::string name)
{
  middleware::cookies::Cookie cookie;

  cookie.name = std::move(name);
  cookie.value = "";
  cookie.path = "/";
  cookie.max_age = 0;
  cookie.http_only = true;
  cookie.secure = false;
  cookie.same_site = "Lax";

  middleware::cookies::set(res, cookie);
}

static void register_cookie_routes(App &app)
{
  app.get("/", [](Request &, Response &res)
  {
    res.send(
      "Cookies example\n"
      "\n"
      "Try:\n"
      "  curl -i -c cookies.txt http://127.0.0.1:8080/cookie/set\n"
      "  curl -i -b cookies.txt http://127.0.0.1:8080/cookie/read\n"
      "  curl -i -b cookies.txt -c cookies.txt http://127.0.0.1:8080/cookie/delete\n"
    );
  });

  app.get("/cookie/set", [](Request &, Response &res)
  {
    set_cookie(
      res,
      "hello",
      "vix",
      3600
    );

    res.json({
      "ok", true,
      "message", "cookie set",
      "name", "hello"
    });
  });

  app.get("/cookie/read", [](Request &req, Response &res)
  {
    auto value =
      middleware::cookies::get(req, "hello");

    if (!value)
    {
      res.status(404).json({
        "ok", false,
        "error", "Cookie not found",
        "name", "hello"
      });
      return;
    }

    res.json({
      "ok", true,
      "name", "hello",
      "value", *value
    });
  });

  app.get("/cookie/delete", [](Request &, Response &res)
  {
    delete_cookie(res, "hello");

    res.json({
      "ok", true,
      "message", "cookie deleted",
      "name", "hello"
    });
  });
}

static void register_theme_routes(App &app)
{
  app.get("/theme/light", [](Request &, Response &res)
  {
    set_cookie(
      res,
      "theme",
      "light",
      60 * 60 * 24 * 30
    );

    res.json({
      "ok", true,
      "theme", "light"
    });
  });

  app.get("/theme/dark", [](Request &, Response &res)
  {
    set_cookie(
      res,
      "theme",
      "dark",
      60 * 60 * 24 * 30
    );

    res.json({
      "ok", true,
      "theme", "dark"
    });
  });

  app.get("/theme", [](Request &req, Response &res)
  {
    auto theme =
      middleware::cookies::get(req, "theme");

    res.json({
      "ok", true,
      "theme", theme ? *theme : "default"
    });
  });
}

int main()
{
  App app;

  install_middleware(app);
  register_cookie_routes(app);
  register_theme_routes(app);

  app.run(8080);
  return 0;
}

Run it

Run:

bash
vix run cookies.cpp

The server listens on:

txt
http://127.0.0.1:8080

Use curl with -c to save cookies into a local cookie jar:

bash
curl -i \
  -c cookies.txt \
  http://127.0.0.1:8080/cookie/set

Expected status:

txt
200 OK

Expected response header:

txt
Set-Cookie: hello=vix; Path=/; Max-Age=3600; HttpOnly; SameSite=Lax

Expected body:

json
{
  "ok": true,
  "message": "cookie set",
  "name": "hello"
}

The cookie is stored by the client.

With curl, it is stored in:

txt
cookies.txt

Use curl with -b to send cookies from the cookie jar:

bash
curl -i \
  -b cookies.txt \
  http://127.0.0.1:8080/cookie/read

Expected body:

json
{
  "ok": true,
  "name": "hello",
  "value": "vix"
}

The route reads the cookie with:

cpp
auto value =
  middleware::cookies::get(req, "hello");

The return type is:

cpp
std::optional<std::string>

So the handler must handle the missing-cookie case.

Call /cookie/read without sending cookies:

bash
curl -i http://127.0.0.1:8080/cookie/read

Expected status:

txt
404 Not Found

Expected body:

json
{
  "ok": false,
  "error": "Cookie not found",
  "name": "hello"
}

Use -b to send the cookie and -c to update the cookie jar:

bash
curl -i \
  -b cookies.txt \
  -c cookies.txt \
  http://127.0.0.1:8080/cookie/delete

Expected header shape:

txt
Set-Cookie: hello=; Path=/; Max-Age=0; HttpOnly; SameSite=Lax

The important part is:

txt
Max-Age=0

That tells the browser to remove the cookie.

Try reading again:

bash
curl -i \
  -b cookies.txt \
  http://127.0.0.1:8080/cookie/read

Expected status:

txt
404 Not Found

Theme preference example

Set dark theme:

bash
curl -i \
  -c cookies.txt \
  http://127.0.0.1:8080/theme/dark

Read theme:

bash
curl -i \
  -b cookies.txt \
  http://127.0.0.1:8080/theme

Expected body:

json
{
  "ok": true,
  "theme": "dark"
}

Set light theme:

bash
curl -i \
  -b cookies.txt \
  -c cookies.txt \
  http://127.0.0.1:8080/theme/light

Read again:

bash
curl -i \
  -b cookies.txt \
  http://127.0.0.1:8080/theme

Expected body:

json
{
  "ok": true,
  "theme": "light"
}

This is a good cookie use case because the value is small and not sensitive.

A cookie is represented by:

cpp
middleware::cookies::Cookie cookie;

Example:

cpp
middleware::cookies::Cookie cookie;

cookie.name = "hello";
cookie.value = "vix";
cookie.path = "/";
cookie.max_age = 3600;
cookie.http_only = true;
cookie.secure = false;
cookie.same_site = "Lax";

middleware::cookies::set(res, cookie);

This writes a Set-Cookie response header.

The cookie struct contains:

cpp
struct Cookie
{
  std::string name;
  std::string value;

  std::string path{"/"};
  std::string domain{};
  int max_age{-1};
  bool http_only{true};
  bool secure{false};
  std::string same_site{"Lax"};
};

Meaning:

txt
name
  cookie name

value
  cookie value

path
  URL path where the cookie applies

domain
  optional domain

max_age
  lifetime in seconds, -1 means no Max-Age

http_only
  blocks JavaScript access when true

secure
  sends cookie only over HTTPS when true

same_site
  browser cross-site policy

Use:

cpp
auto value =
  middleware::cookies::get(req, "theme");

Then:

cpp
if (value)
{
  res.json({
    "theme", *value
  });
}

The cookie may be missing, so use std::optional.

Parse all cookies

You can parse the full Cookie header:

cpp
auto cookies =
  middleware::cookies::parse(req);

Example:

cpp
app.get("/cookie/all", [](Request &req, Response &res)
{
  auto all = middleware::cookies::parse(req);

  res.json({
    "ok", true,
    "count", static_cast<long long>(all.size())
  });
});

Use get(...) when you only need one cookie.

Use parse(...) when you need several values.

To delete a cookie, set the same name and path with:

txt
Max-Age=0

Example:

cpp
middleware::cookies::Cookie cookie;

cookie.name = "theme";
cookie.value = "";
cookie.path = "/";
cookie.max_age = 0;
cookie.http_only = true;
cookie.secure = false;
cookie.same_site = "Lax";

middleware::cookies::set(res, cookie);

The name and path should match the cookie you want to remove.

HttpOnly

Use:

cpp
cookie.http_only = true;

This adds:

txt
HttpOnly

HttpOnly means browser JavaScript cannot read the cookie with document.cookie.

Use it for sensitive cookies such as:

txt
session ids
auth tokens
CSRF-related server cookies

For a harmless theme preference, HttpOnly can be false if JavaScript needs to read it.

For server-owned cookies, keep it true.

Secure

Use:

cpp
cookie.secure = true;

This adds:

txt
Secure

A Secure cookie is sent only over HTTPS.

For local HTTP development, secure = false is common.

For production HTTPS apps, use:

cpp
cookie.secure = true;

especially for authentication and session cookies.

SameSite

Use:

cpp
cookie.same_site = "Lax";

Common values are:

txt
Lax
Strict
None

A practical default is:

txt
Lax

Use None only when the cookie must be sent cross-site.

Modern browsers require Secure when SameSite=None.

So for cross-site production cookies:

cpp
cookie.same_site = "None";
cookie.secure = true;

Use:

cpp
cookie.path = "/";

That makes the cookie available to the whole site.

You can limit it:

cpp
cookie.path = "/admin";

Then the browser sends it only for matching paths.

Use a narrow path when a cookie belongs only to a specific area of the app.

Most apps can leave the domain empty:

cpp
cookie.domain = "";

That makes the browser use the current host.

Set a domain only when you understand the browser cookie domain rules.

Example shape:

cpp
cookie.domain = ".example.com";

Use this only when subdomains need to share a cookie.

Important limitation

The current native response header map stores one value per header key.

That means repeated Set-Cookie headers may not be preserved by the current response API.

For simple examples, this is fine:

cpp
middleware::cookies::set(res, cookie);

But if you need to set multiple cookies in the same response, make sure the response layer supports multiple Set-Cookie headers before relying on it.

This is important because HTTP cookies normally require separate Set-Cookie headers.

Cookies vs sessions

Cookies store data on the client.

Sessions store data on the server and usually keep only a session id in the cookie.

Cookie example:

txt
theme=dark

Session example:

txt
sid=abc123

The server uses sid to load data such as:

txt
user id
cart
flash messages
login state

Use cookies for small client values.

Use sessions for server-managed state.

Cookies vs JWT

A cookie is a transport/storage mechanism.

A JWT is a token format.

You can put a JWT in a cookie, but that is a separate authentication design choice.

Simple rule:

txt
cookie
  browser storage and transport

session
  server-side state using a cookie id

JWT
  signed token containing claims

Security notes

Do not store sensitive data directly in plain cookies.

Avoid this:

txt
role=admin
user_id=123
balance=5000

The client can modify plain cookies.

For sensitive state, use:

txt
server-side sessions
signed cookies
encrypted cookies
JWT with verification
database-backed state

A theme preference is fine in a plain cookie.

Authentication state should be protected.

Production defaults

For session or auth-related cookies in production, prefer:

txt
HttpOnly = true
Secure = true
SameSite = Lax or Strict
Path = /
short and intentional lifetime

For cross-site applications, such as frontend and API on different sites, cookie rules are stricter.

You may need:

txt
SameSite=None
Secure=true
CORS with credentials
HTTPS

Design that carefully.

Complete test flow

Run:

bash
vix run cookies.cpp

Set cookie:

bash
curl -i \
  -c cookies.txt \
  http://127.0.0.1:8080/cookie/set

Read cookie:

bash
curl -i \
  -b cookies.txt \
  http://127.0.0.1:8080/cookie/read

Delete cookie:

bash
curl -i \
  -b cookies.txt \
  -c cookies.txt \
  http://127.0.0.1:8080/cookie/delete

Read after delete:

bash
curl -i \
  -b cookies.txt \
  http://127.0.0.1:8080/cookie/read

Theme example:

bash
curl -i -c cookies.txt http://127.0.0.1:8080/theme/dark
curl -i -b cookies.txt http://127.0.0.1:8080/theme
curl -i -b cookies.txt -c cookies.txt http://127.0.0.1:8080/theme/light
curl -i -b cookies.txt http://127.0.0.1:8080/theme

Summary

Use cookies for small client-side values.

Set a cookie:

cpp
middleware::cookies::Cookie cookie;

cookie.name = "theme";
cookie.value = "dark";
cookie.path = "/";
cookie.max_age = 3600;
cookie.http_only = true;
cookie.secure = false;
cookie.same_site = "Lax";

middleware::cookies::set(res, cookie);

Read a cookie:

cpp
auto theme =
  middleware::cookies::get(req, "theme");

Delete a cookie:

cpp
cookie.name = "theme";
cookie.value = "";
cookie.path = "/";
cookie.max_age = 0;

middleware::cookies::set(res, cookie);

The mental model is:

txt
Set-Cookie response header
  tells browser to store or delete a cookie

Cookie request header
  sends stored cookies back to the server

Vix cookie helpers
  build, parse, read, and write cookie values

Released under the MIT License.