Skip to content

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

typescript
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

typescript
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

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

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

typescript
const updated = auth.updateSession("sess_abc123", {
  lastActivity: Date.now(),
  page: "/dashboard",
});

if (updated) {
  console.log("Session updated:", updated.data);
}

Destroying Sessions

typescript
// 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

typescript
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

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

typescript
const auth = createAuth({
  jwtSecret: "my-secret",
  sessionTtl: 3600,              // 1 hour
  sessionRefreshThreshold: 300,  // Auto-refresh if accessed within 5 minutes of expiry
});

Complete Example

typescript
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 sessionRefreshThreshold to 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

Released under the MIT License.