Vix.cpp v2.8.5 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.