0
# Cookies Support
1
2
The Ktor HTTP Client Core provides comprehensive cookie management functionality through the `HttpCookies` plugin. This allows automatic handling of HTTP cookies across requests with configurable storage backends and support for custom cookie storage implementations.
3
4
## Core Cookie API
5
6
### HttpCookies Plugin
7
8
The main plugin for cookie management that automatically handles cookie storage and retrieval.
9
10
```kotlin { .api }
11
object HttpCookies : HttpClientPlugin<HttpCookies.Config, HttpCookies> {
12
class Config {
13
var storage: CookiesStorage = AcceptAllCookiesStorage()
14
15
fun default()
16
fun storage(storage: CookiesStorage)
17
}
18
}
19
```
20
21
### CookiesStorage Interface
22
23
Base interface for implementing custom cookie storage backends.
24
25
```kotlin { .api }
26
interface CookiesStorage {
27
suspend fun get(requestUrl: Url): List<Cookie>
28
suspend fun addCookie(requestUrl: Url, cookie: Cookie)
29
fun close()
30
}
31
```
32
33
## Built-in Storage Implementations
34
35
### AcceptAllCookiesStorage
36
37
Default storage implementation that accepts and stores all cookies with in-memory storage.
38
39
```kotlin { .api }
40
class AcceptAllCookiesStorage : CookiesStorage {
41
override suspend fun get(requestUrl: Url): List<Cookie>
42
override suspend fun addCookie(requestUrl: Url, cookie: Cookie)
43
override fun close()
44
}
45
```
46
47
### ConstantCookiesStorage
48
49
Read-only storage implementation that provides a fixed set of cookies for all requests.
50
51
```kotlin { .api }
52
class ConstantCookiesStorage(
53
private val cookies: List<Cookie>
54
) : CookiesStorage {
55
constructor(vararg cookies: Cookie)
56
57
override suspend fun get(requestUrl: Url): List<Cookie>
58
override suspend fun addCookie(requestUrl: Url, cookie: Cookie)
59
override fun close()
60
}
61
```
62
63
## Cookie Data Types
64
65
### Cookie Class
66
67
Represents an HTTP cookie with all its attributes.
68
69
```kotlin { .api }
70
data class Cookie(
71
val name: String,
72
val value: String,
73
val encoding: CookieEncoding = CookieEncoding.URI_ENCODING,
74
val maxAge: Int = 0,
75
val expires: GMTDate? = null,
76
val domain: String? = null,
77
val path: String? = null,
78
val secure: Boolean = false,
79
val httpOnly: Boolean = false,
80
val extensions: Map<String, String?> = emptyMap()
81
) {
82
fun copy(
83
name: String = this.name,
84
value: String = this.value,
85
encoding: CookieEncoding = this.encoding,
86
maxAge: Int = this.maxAge,
87
expires: GMTDate? = this.expires,
88
domain: String? = this.domain,
89
path: String? = this.path,
90
secure: Boolean = this.secure,
91
httpOnly: Boolean = this.httpOnly,
92
extensions: Map<String, String?> = this.extensions
93
): Cookie
94
}
95
96
enum class CookieEncoding {
97
URI_ENCODING,
98
DQUOTES,
99
RAW
100
}
101
```
102
103
## Basic Usage
104
105
### Simple Cookie Handling
106
107
```kotlin
108
val client = HttpClient {
109
install(HttpCookies)
110
}
111
112
// First request - server sets cookies
113
val loginResponse = client.post("https://example.com/login") {
114
setBody("username=john&password=secret")
115
contentType(ContentType.Application.FormUrlEncoded)
116
}
117
118
// Subsequent requests automatically include cookies
119
val profileResponse = client.get("https://example.com/profile")
120
// Cookies from login are automatically sent
121
122
client.close()
123
```
124
125
### Custom Storage Configuration
126
127
```kotlin
128
val client = HttpClient {
129
install(HttpCookies) {
130
storage = AcceptAllCookiesStorage()
131
}
132
}
133
134
// Or with constant cookies
135
val client2 = HttpClient {
136
install(HttpCookies) {
137
storage = ConstantCookiesStorage(
138
Cookie("session_id", "abc123"),
139
Cookie("user_pref", "dark_mode")
140
)
141
}
142
}
143
```
144
145
### Manual Cookie Management
146
147
```kotlin
148
val cookieStorage = AcceptAllCookiesStorage()
149
150
val client = HttpClient {
151
install(HttpCookies) {
152
storage = cookieStorage
153
}
154
}
155
156
// Add cookies manually
157
cookieStorage.addCookie(
158
Url("https://example.com"),
159
Cookie(
160
name = "auth_token",
161
value = "bearer_xyz789",
162
domain = "example.com",
163
path = "/api",
164
secure = true,
165
httpOnly = true,
166
maxAge = 3600 // 1 hour
167
)
168
)
169
170
// Cookies will be included in matching requests
171
val response = client.get("https://example.com/api/data")
172
```
173
174
## Advanced Cookie Features
175
176
### Cookie Attributes
177
178
```kotlin
179
val secureCookie = Cookie(
180
name = "secure_session",
181
value = "encrypted_data",
182
domain = ".example.com", // Available to all subdomains
183
path = "/secure", // Only for /secure paths
184
secure = true, // HTTPS only
185
httpOnly = true, // No JavaScript access
186
maxAge = 7200, // 2 hours lifetime
187
extensions = mapOf(
188
"SameSite" to "Strict" // CSRF protection
189
)
190
)
191
```
192
193
### Domain and Path Matching
194
195
Cookies are automatically filtered based on domain and path matching rules:
196
197
```kotlin
198
val client = HttpClient {
199
install(HttpCookies) {
200
storage = AcceptAllCookiesStorage()
201
}
202
}
203
204
// Set cookies with different scopes
205
client.get("https://api.example.com/login") // May set cookies for .example.com
206
client.get("https://app.example.com/dashboard") // Gets cookies for .example.com
207
client.get("https://other.com/data") // No cookies from example.com
208
```
209
210
### Cookie Encoding
211
212
```kotlin
213
val encodedCookie = Cookie(
214
name = "special_chars",
215
value = "hello world & more!",
216
encoding = CookieEncoding.URI_ENCODING // URL-encodes special characters
217
)
218
219
val quotedCookie = Cookie(
220
name = "quoted_value",
221
value = "contains spaces",
222
encoding = CookieEncoding.DQUOTES // Wraps in double quotes
223
)
224
225
val rawCookie = Cookie(
226
name = "raw_value",
227
value = "no-encoding-needed",
228
encoding = CookieEncoding.RAW // No encoding applied
229
)
230
```
231
232
## Custom Storage Implementation
233
234
### Thread-Safe Cookie Storage
235
236
```kotlin
237
class ThreadSafeCookieStorage : CookiesStorage {
238
private val cookies = mutableMapOf<String, MutableList<Cookie>>()
239
private val mutex = Mutex()
240
241
override suspend fun get(requestUrl: Url): List<Cookie> = mutex.withLock {
242
val host = requestUrl.host
243
return cookies[host]?.filter { cookie ->
244
// Apply domain and path matching logic
245
matchesDomain(cookie.domain, host) &&
246
matchesPath(cookie.path, requestUrl.encodedPath)
247
} ?: emptyList()
248
}
249
250
override suspend fun addCookie(requestUrl: Url, cookie: Cookie) = mutex.withLock {
251
val host = requestUrl.host
252
cookies.getOrPut(host) { mutableListOf() }.add(cookie)
253
}
254
255
override fun close() {
256
// Cleanup resources
257
}
258
259
private fun matchesDomain(cookieDomain: String?, requestHost: String): Boolean {
260
// Implement domain matching rules
261
return cookieDomain == null || requestHost.endsWith(cookieDomain)
262
}
263
264
private fun matchesPath(cookiePath: String?, requestPath: String): Boolean {
265
// Implement path matching rules
266
return cookiePath == null || requestPath.startsWith(cookiePath)
267
}
268
}
269
```
270
271
### Persistent Cookie Storage
272
273
```kotlin
274
class FileCookieStorage(private val file: File) : CookiesStorage {
275
private val cookies = mutableMapOf<String, MutableList<Cookie>>()
276
277
init {
278
loadCookies()
279
}
280
281
override suspend fun get(requestUrl: Url): List<Cookie> {
282
return cookies[requestUrl.host] ?: emptyList()
283
}
284
285
override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
286
cookies.getOrPut(requestUrl.host) { mutableListOf() }.add(cookie)
287
saveCookies()
288
}
289
290
override fun close() {
291
saveCookies()
292
}
293
294
private fun loadCookies() {
295
if (file.exists()) {
296
// Load cookies from file (implementation dependent)
297
}
298
}
299
300
private fun saveCookies() {
301
// Save cookies to file (implementation dependent)
302
}
303
}
304
```
305
306
## Cookie Security
307
308
### Secure Cookie Practices
309
310
```kotlin
311
val client = HttpClient {
312
install(HttpCookies) {
313
storage = AcceptAllCookiesStorage()
314
}
315
}
316
317
// Always use secure cookies for sensitive data
318
val secureCookie = Cookie(
319
name = "auth_session",
320
value = "encrypted_token",
321
secure = true, // Only send over HTTPS
322
httpOnly = true, // Prevent XSS attacks
323
extensions = mapOf(
324
"SameSite" to "Strict" // Prevent CSRF attacks
325
)
326
)
327
```
328
329
### Cookie Filtering
330
331
```kotlin
332
class FilteringCookieStorage(
333
private val delegate: CookiesStorage,
334
private val allowedDomains: Set<String>
335
) : CookiesStorage {
336
337
override suspend fun get(requestUrl: Url): List<Cookie> {
338
return if (requestUrl.host in allowedDomains) {
339
delegate.get(requestUrl)
340
} else {
341
emptyList()
342
}
343
}
344
345
override suspend fun addCookie(requestUrl: Url, cookie: Cookie) {
346
if (requestUrl.host in allowedDomains) {
347
delegate.addCookie(requestUrl, cookie)
348
}
349
}
350
351
override fun close() = delegate.close()
352
}
353
354
val client = HttpClient {
355
install(HttpCookies) {
356
storage = FilteringCookieStorage(
357
AcceptAllCookiesStorage(),
358
setOf("api.example.com", "secure.example.com")
359
)
360
}
361
}
362
```
363
364
## Cookie Inspection and Debugging
365
366
### Accessing Cookie Storage
367
368
```kotlin
369
val cookieStorage = AcceptAllCookiesStorage()
370
371
val client = HttpClient {
372
install(HttpCookies) {
373
storage = cookieStorage
374
}
375
}
376
377
// Make requests that set cookies
378
client.get("https://example.com/login")
379
380
// Inspect stored cookies
381
val storedCookies = cookieStorage.get(Url("https://example.com"))
382
println("Stored cookies: ${storedCookies.joinToString { "${it.name}=${it.value}" }}")
383
```
384
385
### Request Cookie Inspection
386
387
```kotlin
388
val client = HttpClient {
389
install(HttpCookies)
390
391
install(HttpSend) {
392
intercept { request ->
393
// Log cookies being sent
394
val cookieHeader = request.headers["Cookie"]
395
println("Sending cookies: $cookieHeader")
396
397
execute(request)
398
}
399
}
400
}
401
```
402
403
## Best Practices
404
405
1. **Use secure cookies**: Always set `secure` and `httpOnly` flags for sensitive cookies
406
2. **Implement proper storage**: Use persistent storage for long-lived applications
407
3. **Handle cookie expiration**: Check and clean up expired cookies regularly
408
4. **Domain validation**: Validate cookie domains to prevent security issues
409
5. **Thread safety**: Ensure custom storage implementations are thread-safe
410
6. **Memory management**: Be mindful of memory usage in long-running applications with many cookies
411
7. **CSRF protection**: Use SameSite attribute for additional security
412
8. **Cookie size limits**: Be aware of cookie size limitations (typically 4KB per cookie)