···44import { secureHeaders } from "hono/secure-headers";
55import { logger } from "hono/logger";
66import { errorHandler } from "./middleware/error";
77+import authRoutes from "./routes/auth";
7889const app = new Hono();
910···4243 credentials: true,
4344 }),
4445);
4646+4747+// Mount routes
4848+app.route("/api/auth", authRoutes);
45494650// Health check endpoint
4751app.get("/api/health", (c) => {
+1
packages/api/src/utils/index.ts
···22export * from "./string.utils";
33export * from "./encryption.utils";
44export * from "./validation.utils";
55+export * from "./session-security";
+67
packages/api/src/utils/session-security.ts
···11+import { Context } from "hono";
22+33+export interface SessionFingerprint {
44+ userAgent: string;
55+ ipAddress: string;
66+ createdAt: number;
77+}
88+99+/**
1010+ * Session Security Service
1111+ * Provides session replay protection and fingerprinting for Hono
1212+ */
1313+export class SessionSecurityService {
1414+ /**
1515+ * Generate a session fingerprint from request headers
1616+ */
1717+ static generateFingerprint(c: Context): SessionFingerprint {
1818+ const userAgent = c.req.header("user-agent") || "unknown";
1919+ const forwardedFor = c.req.header("x-forwarded-for");
2020+ const ipAddress = forwardedFor?.split(",")[0].trim() || c.req.header("client-ip") || "unknown";
2121+2222+ return {
2323+ userAgent,
2424+ ipAddress,
2525+ createdAt: Date.now(),
2626+ };
2727+ }
2828+2929+ /**
3030+ * Verify session fingerprint matches current request
3131+ * Helps detect session hijacking
3232+ */
3333+ static verifyFingerprint(
3434+ stored: SessionFingerprint,
3535+ current: SessionFingerprint,
3636+ ): boolean {
3737+ // User agent must match exactly
3838+ if (stored.userAgent !== current.userAgent) {
3939+ console.warn("Session fingerprint mismatch: User-Agent changed");
4040+ return false;
4141+ }
4242+4343+ // IP can change (mobile networks, VPN) but log if it does
4444+ if (stored.ipAddress !== current.ipAddress) {
4545+ console.info(
4646+ `Session IP changed: ${stored.ipAddress} -> ${current.ipAddress}`,
4747+ );
4848+ // Don't fail - just log for monitoring
4949+ }
5050+5151+ return true;
5252+ }
5353+}
5454+5555+/**
5656+ * Add session fingerprint to new sessions
5757+ * Call this in oauth-callback when creating session
5858+ */
5959+export function createSecureSessionData(
6060+ c: Context,
6161+ did: string,
6262+): { did: string; fingerprint: SessionFingerprint } {
6363+ return {
6464+ did,
6565+ fingerprint: SessionSecurityService.generateFingerprint(c),
6666+ };
6767+}