Session storage
User authentication sessions, API tokens, and short-term cache results need to be read quickly on every request, but do not need to persist indefinitely.
Layeron KV Storage (storage.kv) is designed exactly for this. Backed by Cloudflare KV, it offers near-zero read latency from global edge locations and supports Time-to-Live (TTL) parameters to automatically clean up expired sessions.
Code Implementation
Section titled “Code Implementation”This example demonstrates setting up a low-latency session KV namespace, logging in users (creating sessions with standard or “Remember Me” TTLs), verifying sessions, and logging out (deleting sessions).
import { backend } from "@layeron/core"import { storage } from "@layeron/modules"
const app = backend()
// 1. Declare the low-latency session KV storeconst sessionsStore = storage.kv({ name: "user-sessions", namespace: "auth", ttlSeconds: 86400, // Standard sessions expire after 24 hours (86,400 seconds)})
app.use(sessionsStore)
// 2. Route: Create Session on Loginapp.post("/api/auth/login", async (request) => { const body = await request.json() as { email: string; rememberMe?: boolean } const sessionId = crypto.randomUUID()
const sessionData = { userId: "usr_100", email: body.email, roles: ["admin"], createdAt: new Date().toISOString(), }
// Determine TTL (Remember Me sessions live for 30 days) const ttlOverride = body.rememberMe ? 30 * 24 * 60 * 60 // 30 days in seconds (2,592,000s) : undefined; // Falls back to default 24 hours configured in constructor
// Save session details to KV await sessionsStore.put(`session:${sessionId}`, JSON.stringify(sessionData), { contentType: "application/json", ...(ttlOverride ? { ttlSeconds: ttlOverride } : {}), // Apply per-key TTL override })
// Return the session token to be stored as a cookie return Response.json({ status: "logged_in", token: sessionId, })})
// 3. Route: Validate Session on API requestapp.get("/api/profile", async (request) => { const authHeader = request.headers.get("authorization") if (!authHeader?.startsWith("Bearer ")) { return new Response("Unauthorized", { status: 401 }) }
const token = authHeader.split(" ")[1] const sessionHandle = await sessionsStore.get(`session:${token}`)
// If the session does not exist or has expired, get() returns null automatically if (!sessionHandle) { return new Response("Session expired or invalid", { status: 401 }) }
// Parse JSON session payload directly from the read handle const userSession = await sessionHandle.json<{ userId: string; email: string; roles: string[] }>()
return Response.json({ message: `Hello, ${userSession.email}!`, roles: userSession.roles, })})
// 4. Route: Logout (Delete Session)app.post("/api/auth/logout", async (request) => { const authHeader = request.headers.get("authorization") const token = authHeader?.split(" ")[1]
if (token) { // Explicitly delete the session key from KV storage await sessionsStore.delete(`session:${token}`) }
return Response.json({ loggedOut: true })})How It Works
Section titled “How It Works”- Edge-Cached Latency: Verifying sessions is a read-heavy operation. Cloudflare KV automatically caches keys close to the user at the nearest edge routing node, meaning session verification takes less than 1-2 milliseconds for active users.
- Global Expiration Defaults: When no
ttlSecondsoption is supplied during a.put()write, the Storage Product Worker defaults to the86400seconds (24 hours) lifetime declared in the KV constructor. - Per-Key Override Flexibility: By passing a custom
{ ttlSeconds: 2592000 }on.put(), you override the default for that specific key. This is perfect for supporting both short-lived guest sessions and long-lived “Remember Me” persistent tokens. - Garbage Collection: Expired sessions are deleted by Cloudflare KV asynchronously. There are no cleanup scripts to schedule or database indexes to prune.