Signed session
createSession (from @bext-stack/framework/auth) sets an HMAC-signed cookie; read() verifies the signature and the expiry on every request. Tampered values fail constant-time comparison and the request is treated as anonymous. The signer is pure-JS HMAC-SHA256 — no node:crypto dependency.
Tip
Expiry is baked into the signed payload, not just the cookie Max-Age — a token copied from DevTools still expires server-side. Always read the secret from an environment variable rather than a constant. The same module also provides parseCookies, PKCE, and OIDC authorization-URL building.
Status
import { createSession } from "@bext-stack/framework/auth";
// Pure-JS HMAC-SHA256 signer — no node:crypto, runs in any isolate.
const session = createSession<{ name: string }>({
secret: process.env.SESSION_SECRET!,
cookie: "sid",
maxAgeSecs: 600, // expiry is signed into the payload, not just the cookie
});
export async function loader({ request }) {
// verifies the signature + expiry; tampered / expired → null
return { session: session.read(request) };
}
export async function action({ request }) {
const form = await request.formData();
if (form.get("op") === "logout")
return new Response(null, { status: 303, headers: { location: "/", "set-cookie": session.clearCookie() } });
const name = String(form.get("name"));
return new Response(null, {
status: 303,
headers: { location: "/", "set-cookie": session.cookie({ name, loginAt: Date.now() }) },
});
}