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-key API key for initial authentication.
  • The session cookie generated by Kong.

The flow is:

  1. The client sends the API key.
  2. Key Auth validates it and identifies the Consumer.
  3. Session creates a cookie representing that identity.
  4. The client stores the cookie.
  5. On later requests, Session validates the cookie.
  6. Key Auth recognizes that the identity came from a valid session.
  7. 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.

Session and Key Auth flow in Kong

3. Authenticated and anonymous Consumers

The lab uses two Consumers:

  • session-client represents the authenticated client and owns the API key.
  • anonymous-session represents 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 resourceFunction in Kong
Session KongPluginManages the cookie and session data
Key Auth KongPluginValidates the initial credential
SecretCreates the API key
Authenticated KongConsumerRepresents the valid client
Request Termination KongPluginBuilds the 403 response
Anonymous KongConsumerReceives unauthenticated requests
HTTPRoutePublishes 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: cookie stores encrypted data in the cookie.
  • cookie_http_only: true prevents JavaScript from reading it.
  • cookie_same_site: Strict limits cross-site sending.
  • secret cryptographically 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

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
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.

Official sources