Kit defaults to using cookie-based sessions.
The session middleware is configured in the :cookie-session-config of the :handler/ring component. Session timeout is specified in seconds and defaults to 24 hours (i.e. 86400 seconds) of inactivity. Here is the default configuration. The business logic is provided by ring.middleware.session.cookie/cookie-store.
{:cookie-secret #or [#env COOKIE_SECRET "16charsecrethere"]
:cookie-name "<project-ns>"
:cookie-default-max-age 86400}Ring tracks sessions using the request map and the current session will be found under the :session key.
Below we have a simple example of interaction with the session.
(ns myapp.home
(:require
[ring.util.response :refer [response]]))
(defn set-user! [id {session :session}]
(-> (response (str "User set to: " id))
(assoc :session (assoc session :user id))
(assoc :headers {"Content-Type" "text/plain"})))
(defn remove-user! [{session :session}]
(-> (response "User removed")
(assoc :session (dissoc session :user))
(assoc :headers {"Content-Type" "text/plain"})))
(defn clear-session! []
(-> (response "Session cleared")
(assoc :session nil)
(assoc :headers {"Content-Type" "text/plain"})))
(def app-routes
[""
{:middleware [middleware/wrap-formats]}
["/login/:id" {:get (fn [{:keys [path-params] :as req}]
(set-user! (:id path-params) req))}]
["/remove" {:get remove-user!}]
["/logout" {:get clear-session!]])Flash sessions have a lifespan of a single request, these can be accessed using the :flash key instead of the :session key used for regular sessions.
Cookies are found under the :cookies key of the request, eg:
{:cookies {"username" {:value "Bob"}}}
Conversely, to set a cookie on the response we simply update the response map with the desired cookie value:
(-> "response with a cookie" response (assoc-in [:cookies "username" :value] "Alice"))
Cookies can contain the following additional attributes in addition to the :value key:
Java objects such as dates must be explicitly encoded when stored in cookie sessions. The following example illustrates how to use tick library to add a reader for a zoned date-time:
(defn wrap-base
[{:keys [cookie-opts]}]
(let [{:keys [cookie-secret cookie-name cookie-default-max-age]} cookie-opts
cookie-store (session.cookie/cookie-store {:key (.getBytes ^String cookie-secret)
:readers {'inst (fn [x]
(some-> x (tick/parse) (tick/inst)))
'time/zoned-date-time #'tick/zoned-date-time}})]
(fn [handler]
(cond-> handler
true (session/wrap-session {:store cookie-store
:cookie-name cookie-name
:cookie-attrs {:max-age cookie-default-max-age}})
true (cookies/wrap-cookies)))))