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:
theme preference
language preference
visitor id
CSRF token
small browser state
session id2
3
4
5
6
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:
GET /cookie/set
GET /cookie/read
GET /cookie/delete
GET /theme/light
GET /theme/dark
GET /theme2
3
4
5
6
It demonstrates:
setting a cookie
reading a cookie
deleting a cookie
using cookie options
reading cookies from Request
writing Set-Cookie to Response2
3
4
5
6
Header
Use:
#include <vix/middleware.hpp>or include only the cookie helper:
#include <vix/middleware/http/cookies.hpp>The cookie helpers live in:
vix::middleware::cookiesProject structure
Create:
cookies_demo/
└── cookies.cpp2
Create the file:
mkdir cookies_demo
cd cookies_demo
touch cookies.cpp2
3
Source
Open:
cookies.cppAdd:
#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;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
Run it
Run:
vix run cookies.cppThe server listens on:
http://127.0.0.1:8080Set a cookie
Use curl with -c to save cookies into a local cookie jar:
curl -i \
-c cookies.txt \
http://127.0.0.1:8080/cookie/set2
3
Expected status:
200 OKExpected response header:
Set-Cookie: hello=vix; Path=/; Max-Age=3600; HttpOnly; SameSite=LaxExpected body:
{
"ok": true,
"message": "cookie set",
"name": "hello"
}2
3
4
5
The cookie is stored by the client.
With curl, it is stored in:
cookies.txtRead a cookie
Use curl with -b to send cookies from the cookie jar:
curl -i \
-b cookies.txt \
http://127.0.0.1:8080/cookie/read2
3
Expected body:
{
"ok": true,
"name": "hello",
"value": "vix"
}2
3
4
5
The route reads the cookie with:
auto value =
middleware::cookies::get(req, "hello");2
The return type is:
std::optional<std::string>So the handler must handle the missing-cookie case.
Missing cookie
Call /cookie/read without sending cookies:
curl -i http://127.0.0.1:8080/cookie/readExpected status:
404 Not FoundExpected body:
{
"ok": false,
"error": "Cookie not found",
"name": "hello"
}2
3
4
5
Delete a cookie
Use -b to send the cookie and -c to update the cookie jar:
curl -i \
-b cookies.txt \
-c cookies.txt \
http://127.0.0.1:8080/cookie/delete2
3
4
Expected header shape:
Set-Cookie: hello=; Path=/; Max-Age=0; HttpOnly; SameSite=LaxThe important part is:
Max-Age=0That tells the browser to remove the cookie.
Try reading again:
curl -i \
-b cookies.txt \
http://127.0.0.1:8080/cookie/read2
3
Expected status:
404 Not FoundTheme preference example
Set dark theme:
curl -i \
-c cookies.txt \
http://127.0.0.1:8080/theme/dark2
3
Read theme:
curl -i \
-b cookies.txt \
http://127.0.0.1:8080/theme2
3
Expected body:
{
"ok": true,
"theme": "dark"
}2
3
4
Set light theme:
curl -i \
-b cookies.txt \
-c cookies.txt \
http://127.0.0.1:8080/theme/light2
3
4
Read again:
curl -i \
-b cookies.txt \
http://127.0.0.1:8080/theme2
3
Expected body:
{
"ok": true,
"theme": "light"
}2
3
4
This is a good cookie use case because the value is small and not sensitive.
How to create a cookie
A cookie is represented by:
middleware::cookies::Cookie cookie;Example:
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);2
3
4
5
6
7
8
9
10
11
This writes a Set-Cookie response header.
Cookie fields
The cookie struct contains:
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"};
};2
3
4
5
6
7
8
9
10
11
12
Meaning:
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 policy2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Read one cookie
Use:
auto value =
middleware::cookies::get(req, "theme");2
Then:
if (value)
{
res.json({
"theme", *value
});
}2
3
4
5
6
The cookie may be missing, so use std::optional.
Parse all cookies
You can parse the full Cookie header:
auto cookies =
middleware::cookies::parse(req);2
Example:
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())
});
});2
3
4
5
6
7
8
9
Use get(...) when you only need one cookie.
Use parse(...) when you need several values.
Delete a cookie
To delete a cookie, set the same name and path with:
Max-Age=0Example:
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);2
3
4
5
6
7
8
9
10
11
The name and path should match the cookie you want to remove.
HttpOnly
Use:
cookie.http_only = true;This adds:
HttpOnlyHttpOnly means browser JavaScript cannot read the cookie with document.cookie.
Use it for sensitive cookies such as:
session ids
auth tokens
CSRF-related server cookies2
3
For a harmless theme preference, HttpOnly can be false if JavaScript needs to read it.
For server-owned cookies, keep it true.
Secure
Use:
cookie.secure = true;This adds:
SecureA Secure cookie is sent only over HTTPS.
For local HTTP development, secure = false is common.
For production HTTPS apps, use:
cookie.secure = true;especially for authentication and session cookies.
SameSite
Use:
cookie.same_site = "Lax";Common values are:
Lax
Strict
None2
3
A practical default is:
LaxUse None only when the cookie must be sent cross-site.
Modern browsers require Secure when SameSite=None.
So for cross-site production cookies:
cookie.same_site = "None";
cookie.secure = true;2
Cookie path
Use:
cookie.path = "/";That makes the cookie available to the whole site.
You can limit it:
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.
Cookie domain
Most apps can leave the domain empty:
cookie.domain = "";That makes the browser use the current host.
Set a domain only when you understand the browser cookie domain rules.
Example shape:
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:
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:
theme=darkSession example:
sid=abc123The server uses sid to load data such as:
user id
cart
flash messages
login state2
3
4
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:
cookie
browser storage and transport
session
server-side state using a cookie id
JWT
signed token containing claims2
3
4
5
6
7
8
Security notes
Do not store sensitive data directly in plain cookies.
Avoid this:
role=admin
user_id=123
balance=50002
3
The client can modify plain cookies.
For sensitive state, use:
server-side sessions
signed cookies
encrypted cookies
JWT with verification
database-backed state2
3
4
5
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:
HttpOnly = true
Secure = true
SameSite = Lax or Strict
Path = /
short and intentional lifetime2
3
4
5
For cross-site applications, such as frontend and API on different sites, cookie rules are stricter.
You may need:
SameSite=None
Secure=true
CORS with credentials
HTTPS2
3
4
Design that carefully.
Complete test flow
Run:
vix run cookies.cppSet cookie:
curl -i \
-c cookies.txt \
http://127.0.0.1:8080/cookie/set2
3
Read cookie:
curl -i \
-b cookies.txt \
http://127.0.0.1:8080/cookie/read2
3
Delete cookie:
curl -i \
-b cookies.txt \
-c cookies.txt \
http://127.0.0.1:8080/cookie/delete2
3
4
Read after delete:
curl -i \
-b cookies.txt \
http://127.0.0.1:8080/cookie/read2
3
Theme example:
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/theme2
3
4
Summary
Use cookies for small client-side values.
Set a cookie:
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);2
3
4
5
6
7
8
9
10
11
Read a cookie:
auto theme =
middleware::cookies::get(req, "theme");2
Delete a cookie:
cookie.name = "theme";
cookie.value = "";
cookie.path = "/";
cookie.max_age = 0;
middleware::cookies::set(res, cookie);2
3
4
5
6
The mental model is:
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 values2
3
4
5
6
7
8