Session Management
Kyrin's session system provides in-memory session storage with automatic expiry and refresh. Sessions are useful for tracking authenticated users across requests without re-verifying tokens every time.
Overview
Sessions in Kyrin are stored in memory and identified by a unique session ID. Each session contains:
- User ID — Who the session belongs to
- Data — Arbitrary payload (role, permissions, etc.)
- Timestamps — Creation, expiry, and last access time
Creating Sessions
import { createAuth } from "kyrin";
const auth = createAuth({ jwtSecret: "my-secret" });
// Create a session with custom data
const session = auth.createSession("user-42", {
role: "admin",
ip: "192.168.1.1",
lastLogin: Date.now(),
});
console.log(session.id); // "sess_abc123..."
console.log(session.userId); // "user-42"
console.log(session.data.role); // "admin"
console.log(session.data.ip); // "192.168.1.1"
console.log(session.expiresAt); // e.g. 1744000000000 (ms timestamp)Session Interface
interface Session {
id: string; // Unique session ID (auto-generated)
userId: string; // The authenticated user's ID
data: SessionData; // Custom payload
createdAt: number; // Creation timestamp (ms)
expiresAt: number; // Expiry timestamp (ms)
lastAccessedAt: number; // Last access timestamp (ms)
}
interface SessionData {
userId: string;
role?: string;
[key: string]: unknown; // Any additional data you want to store
}Retrieving Sessions
const session = auth.getSession("sess_abc123");
if (session) {
console.log(session.data);
} else {
// Session not found or expired
console.log("Session expired or invalid");
}Refreshing Sessions
refreshSession() extends the session's lifetime by resetting its expiresAt based on the configured TTL. Returns null if the session has expired.
const refreshed = auth.refreshSession("sess_abc123");
if (refreshed) {
console.log("New expiry:", refreshed.expiresAt);
}Updating Sessions
Update the data stored in a session without changing its expiry.
const updated = auth.updateSession("sess_abc123", {
lastActivity: Date.now(),
page: "/dashboard",
});
if (updated) {
console.log("Session updated:", updated.data);
}Destroying Sessions
// Destroy a single session
const destroyed = auth.destroySession("sess_abc123");
// Returns true if the session existed, false otherwise
// Get all sessions for a user
const userSessions = auth.getUserSessions("user-42");
console.log(`User has ${userSessions.length} active sessions`);Standalone Session Functions
For more granular control, you can use the standalone session functions directly.
Configuration
import { setSessionConfig, getSessionConfig } from "kyrin";
setSessionConfig({
ttl: 7200, // Session TTL in seconds (default: 3600)
refreshThreshold: 600, // Extend session if accessed within N seconds of expiry (default: 300)
cookieName: "session_id", // For cookie-based sessions
secure: true, // Only send over HTTPS
sameSite: "Lax", // "Strict" | "Lax" | "None"
});
const config = getSessionConfig();Session CRUD
import {
createSession,
getSession,
refreshSession,
updateSession,
destroySession,
destroyAllUserSessions,
getUserSessions,
cleanupExpiredSessions,
} from "kyrin";
// Create
const session = createSession("user-42", { role: "admin" });
// Read
const s = getSession(session.id);
// Refresh (extend TTL)
refreshSession(session.id);
// Update data
updateSession(session.id, { role: "moderator" });
// Delete single
destroySession(session.id);
// Delete all sessions for a user
destroyAllUserSessions("user-42");
// Clean up expired sessions (returns count of removed sessions)
const removed = cleanupExpiredSessions();
// Get all sessions for a user
const sessions = getUserSessions("user-42");Auto-Refresh Pattern
The sessionRefreshThreshold option enables automatic session extension. If a session is accessed within this many seconds of its expiry, refreshSession() is called automatically.
const auth = createAuth({
jwtSecret: "my-secret",
sessionTtl: 3600, // 1 hour
sessionRefreshThreshold: 300, // Auto-refresh if accessed within 5 minutes of expiry
});Complete Example
import { createAuth } from "kyrin";
const auth = createAuth({
jwtSecret: process.env.JWT_SECRET!,
sessionTtl: 86400, // 24 hours
sessionRefreshThreshold: 3600, // Auto-refresh within 1 hour of expiry
});
// --- Login ---
app.post("/login", async (c) => {
const { userId } = await c.body();
// Sign JWT
const tokens = await auth.signToken(userId);
// Create session
const session = auth.createSession(userId, {
loginTime: Date.now(),
});
return c.json({
accessToken: tokens.accessToken,
sessionId: session.id,
});
});
// --- Session middleware ---
app.use(async (c, next) => {
const sessionId = c.req.headers.get("X-Session-Id");
if (sessionId) {
// This auto-refreshes if within refresh threshold
const session = auth.getSession(sessionId);
if (session) {
c.store.session = session;
// Refresh if close to expiry
auth.refreshSession(sessionId);
}
}
await next();
});
// --- Dashboard (requires session) ---
app.get("/dashboard", async (c) => {
const session = c.store.session;
if (!session) {
return c.json({ error: "No active session" }, 401);
}
return c.json({
message: `Welcome back, ${session.userId}!`,
lastLogin: new Date(session.data.loginTime).toISOString(),
});
});
// --- Logout ---
app.post("/logout", async (c) => {
const sessionId = c.req.headers.get("X-Session-Id");
if (sessionId) {
auth.destroySession(sessionId);
}
return c.json({ message: "Logged out" });
});Best Practices
- Set an appropriate
sessionTtl— shorter for sensitive apps, longer for convenience - Use
sessionRefreshThresholdto keep active sessions alive without forcing re-login - Destroy sessions on logout to prevent reuse
- Call
cleanupExpiredSessions()periodically to free memory (e.g., via a cron job)
Next Steps
- Authentication — JWT tokens and the Auth class
- Role-Based Access Control — Define roles and permissions
- OAuth2 — Social login integration