Session in Kong
The Session plugin lets an authenticated client reuse its identity through a cookie. It does not authenticate clients on its own and must work alongside another mechanism that validates the first request.
This lab combines Session with Key Auth. The first request presents an API key, Kong creates a session, and later requests use only the cookie. We also configure an explicit anonymous branch to prevent requests without either credential from reaching the backend.
This lab continues directly from Installing KIC. It reuses the kong Gateway, the echo Service, and the 192.168.121.200 address assigned by MetalLB to kong-gateway-proxy.
The tests were run with Kong Gateway 3.10.0.16 and Kong Ingress Controller 3.5.
1. What is a session?
A session preserves the result of authentication across multiple requests. Instead of resending the primary credential every time, the client presents a cookie protected by Kong.
The lab uses two credentials:
- The
session-api-keyAPI key for initial authentication. - The session cookie generated by Kong.
The flow is:
- The client sends the API key.
- Key Auth validates it and identifies the Consumer.
- Session creates a cookie representing that identity.
- The client stores the cookie.
- On later requests, Session validates the cookie.
- Key Auth recognizes that the identity came from a valid session.
- The request continues without sending the API key again.
The cookie does not contain the API key. With storage: cookie, it contains encrypted, cryptographically protected session data.
A session reduces repeated exposure of the initial credential but introduces its own lifecycle: creation, renewal, expiration, and logout. It must always be protected with HTTPS and secure cookie attributes.
2. How does Session work in Kong Gateway?
Kong implements this mechanism through the official session plugin. It supports traditional, hybrid, and DB-less topologies and must always be combined with another authentication plugin.
Session has a higher priority than Key Auth, so it examines the request first:
- A valid session restores the authenticated Consumer and credential.
- Without a session, Key Auth can try to authenticate the API key.
- If Key Auth succeeds, Session creates the response cookie.
This combination behaves as a logical OR: a valid session or a valid API key. We therefore need an explicit rejection branch for requests that contain neither.
We configure anonymous: anonymous-session in Key Auth. Without a valid API key, Kong temporarily assigns that Consumer. The request-termination plugin attached to the anonymous Consumer returns 403 Forbidden.
Without this rejection branch, a multiple-authentication configuration can allow an anonymous request to continue.
The diagram shows all three branches. A valid cookie restores the identity. Without a cookie, a valid API key authenticates the Consumer and creates a new session. If neither credential is valid, request-termination stops the request with 403 Forbidden.
3. Authenticated and anonymous Consumers
The lab uses two Consumers:
session-clientrepresents the authenticated client and owns the API key.anonymous-sessionrepresents requests without a valid session or API key.
Their relationship is:
Route /session
|
+-- Session
|
+-- Key Auth
|
+-- valid API key --> session-client --> upstream
|
+-- no credential --> anonymous-session --> 403
request-termination does not authenticate. It only terminates requests that Key Auth assigned to the anonymous Consumer.
4. Configuring Session with KIC
This lab adds three KongPlugin resources, two KongConsumer resources, one Secret, and one HTTPRoute.
4.1. Relationship between Kubernetes and Kong resources
| Kubernetes resource | Function in Kong |
|---|---|
Session KongPlugin | Manages the cookie and session data |
Key Auth KongPlugin | Validates the initial credential |
Secret | Creates the API key |
Authenticated KongConsumer | Represents the valid client |
Request Termination KongPlugin | Builds the 403 response |
Anonymous KongConsumer | Receives unauthenticated requests |
HTTPRoute | Publishes the route and applies Session and Key Auth |
4.2. Create the Session plugin
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: session
namespace: javier
plugin: session
config:
storage: cookie
cookie_secure: false
cookie_http_only: true
cookie_same_site: Strict
secret: session-kic-secret-32-bytes-change-me
storage: cookiestores encrypted data in the cookie.cookie_http_only: trueprevents JavaScript from reading it.cookie_same_site: Strictlimits cross-site sending.secretcryptographically protects the session.
cookie_secure: false is acceptable only because this lab uses HTTP. Production must use true and expose the route through HTTPS.
4.3. Create the Key Auth plugin
The API key is accepted only from apikey. anonymous selects the identity used when initial authentication fails.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: session-key-auth
namespace: javier
plugin: key-auth
config:
key_names:
- apikey
key_in_header: true
key_in_query: false
key_in_body: false
hide_credentials: true
anonymous: anonymous-session
4.4. Create the Key Auth credential
apiVersion: v1
kind: Secret
metadata:
name: session-key-credential
namespace: javier
labels:
konghq.com/credential: key-auth
stringData:
key: session-api-key
The readable key keeps the lab simple. Production credentials must be random and stored securely.
4.5. Create the authenticated Consumer
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
name: session-client
namespace: javier
annotations:
kubernetes.io/ingress.class: kong
username: session-client
credentials:
- session-key-credential
4.6. Create the rejection plugin
This plugin builds the anonymous branch response:
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: session-anonymous-deny
namespace: javier
plugin: request-termination
config:
status_code: 403
message: Forbidden
4.7. Create the anonymous Consumer
The annotation applies request-termination only to this Consumer:
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
name: anonymous-session
namespace: javier
annotations:
kubernetes.io/ingress.class: kong
konghq.com/plugins: session-anonymous-deny
username: anonymous-session
Its username matches anonymous in the Key Auth plugin.
4.8. Create the HTTPRoute
The HTTPRoute applies both plugins involved in authentication:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: session
namespace: javier
annotations:
konghq.com/plugins: "session,session-key-auth"
spec:
parentRefs:
- name: kong
namespace: kong
hostnames:
- echo.javiercd.es
rules:
- matches:
- path:
type: PathPrefix
value: /session
backendRefs:
- name: echo
port: 80
4.9. Apply the manifests
sudo kubectl apply -f 17-session-session-plugin.yaml
sudo kubectl apply -f 17-session-key-auth-plugin.yaml
sudo kubectl apply -f 17-session-secret.yaml
sudo kubectl apply -f 17-session-consumer.yaml
sudo kubectl apply -f 17-session-anonymous-plugin.yaml
sudo kubectl apply -f 17-session-anonymous-consumer.yaml
sudo kubectl apply -f 17-session-httproute.yaml
Check the resources:
sudo kubectl get kongplugin -n javier \
session session-key-auth session-anonymous-deny
sudo kubectl get kongconsumer -n javier \
session-client anonymous-session
sudo kubectl get httproute session -n javier
sudo kubectl describe httproute session -n javier
5. Testing the session
The following responses were captured directly in the VM. The cookie value changes with every authentication.
5.1. Request without credentials
curl -i http://echo.javiercd.es/session
Key Auth assigns the anonymous Consumer and request-termination responds:
HTTP/1.1 403 Forbidden
Date: Sun, 26 Jul 2026 09:02:20 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Content-Length: 23
X-Kong-Response-Latency: 0
Server: kong/3.10.0.16-enterprise-edition
X-Kong-Request-Id: b8feb11a7f653b271d9e0307ef677f7c
{"message":"Forbidden"}
The request does not reach the upstream.
5.2. Initial authentication with an API key
Remove any previous cookie and send the API key. -c stores response cookies:
rm -f cookies.txt
curl -i \
-c cookies.txt \
-H 'apikey: session-api-key' \
http://echo.javiercd.es/session
Kong validates the key, identifies session-client, and returns 200 OK. This is the observed response. The session value is shortened because it is a temporary credential:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 28
Connection: keep-alive
X-App-Name: http-echo
X-App-Version: 1.0.0
Date: Sun, 26 Jul 2026 09:02:20 GMT
Server: kong/3.10.0.16-enterprise-edition
Set-Cookie: session=<encrypted-cookie>; Path=/; SameSite=Strict; HttpOnly
X-Kong-Upstream-Latency: 0
X-Kong-Proxy-Latency: 1
Via: 1.1 kong/3.10.0.16-enterprise-edition
X-Kong-Request-Id: 149a9d133f53693ff98ced2907d7fe05
Hola desde Kong Gateway KIC
Inspect the cookie jar:
sed -n '1,20p' cookies.txt
5.3. Reuse the cookie
Do not send the API key. -b loads the stored cookie:
curl -i \
-b cookies.txt \
http://echo.javiercd.es/session
Session restores the Consumer identity and the request reaches the upstream again. This second response does not contain Set-Cookie:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 28
Connection: keep-alive
X-App-Name: http-echo
X-App-Version: 1.0.0
Date: Sun, 26 Jul 2026 09:02:20 GMT
Server: kong/3.10.0.16-enterprise-edition
X-Kong-Upstream-Latency: 0
X-Kong-Proxy-Latency: 0
Via: 1.1 kong/3.10.0.16-enterprise-edition
X-Kong-Request-Id: c521543370e6515210393866dd02a849
Hola desde Kong Gateway KIC
5.4. Check an invalid cookie
curl -i \
-H 'Cookie: session=valor-manipulado' \
http://echo.javiercd.es/session
Kong cannot validate the session. Because there is no valid API key either, the request ends at the anonymous Consumer:
HTTP/1.1 403 Forbidden
Date: Sun, 26 Jul 2026 09:02:20 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Content-Length: 23
X-Kong-Response-Latency: 0
Server: kong/3.10.0.16-enterprise-edition
X-Kong-Request-Id: e1748807abaf015060939939a9c3db13
{"message":"Forbidden"}
With storage: cookie, deleting cookies.txt ends the session from the client’s perspective. Centralized invalidation and gateway-side storage require storage: kong, a database-backed strategy configured for that topology.
