| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- import { cookies } from "next/headers";
- import { SignJWT, jwtVerify } from "jose";
- export const SESSION_COOKIE_NAME = "auth_session";
- export const SESSION_MAX_AGE_SECONDS = 60 * 60 * 8; // 8 hours
- function getSessionSecretKey() {
- const secret = process.env.SESSION_SECRET;
- if (!secret) {
- throw new Error("SESSION_SECRET environment variable is not set");
- }
- return new TextEncoder().encode(secret);
- }
- /**
- * Create a signed session JWT and store it in a HTTP-only cookie.
- *
- * @param {Object} params
- * @param {string} params.userId - MongoDB user id as string.
- * @param {string} params.role - User role ("branch" | "admin" | "dev").
- * @param {string|null} params.branchId - Branch id or null.
- * @returns {Promise<string>} The signed JWT.
- */
- export async function createSession({ userId, role, branchId }) {
- if (!userId || !role) {
- throw new Error("createSession requires userId and role");
- }
- const payload = {
- userId,
- role,
- branchId: branchId ?? null,
- };
- const jwt = await new SignJWT(payload)
- .setProtectedHeader({ alg: "HS256", typ: "JWT" })
- .setIssuedAt()
- .setExpirationTime(`${SESSION_MAX_AGE_SECONDS}s`)
- .sign(getSessionSecretKey());
- const cookieStore = cookies();
- cookieStore.set(SESSION_COOKIE_NAME, jwt, {
- httpOnly: true,
- secure: process.env.NODE_ENV === "production",
- sameSite: "lax",
- path: "/",
- maxAge: SESSION_MAX_AGE_SECONDS,
- });
- return jwt;
- }
- /**
- * Read the current session from the HTTP-only cookie.
- *
- * @returns {Promise<{ userId: string, role: string, branchId: string | null } | null>}
- * The session payload, or null if no valid session exists.
- */
- export async function getSession() {
- const cookieStore = cookies();
- const cookie = cookieStore.get(SESSION_COOKIE_NAME);
- if (!cookie?.value) {
- return null;
- }
- const secretKey = getSessionSecretKey();
- try {
- const { payload } = await jwtVerify(cookie.value, secretKey);
- const { userId, role, branchId } = payload;
- if (typeof userId !== "string" || typeof role !== "string") {
- return null;
- }
- return {
- userId,
- role,
- branchId: typeof branchId === "string" ? branchId : null,
- };
- } catch (error) {
- // Invalid or expired token: clear the cookie for hygiene and return null
- const store = cookies();
- store.set(SESSION_COOKIE_NAME, "", {
- httpOnly: true,
- secure: process.env.NODE_ENV === "production",
- sameSite: "lax",
- path: "/",
- maxAge: 0,
- });
- return null;
- }
- }
- /**
- * Destroy the current session by clearing the session cookie.
- */
- export function destroySession() {
- const cookieStore = cookies();
- cookieStore.set(SESSION_COOKIE_NAME, "", {
- httpOnly: true,
- secure: process.env.NODE_ENV === "production",
- sameSite: "lax",
- path: "/",
- maxAge: 0,
- });
- }
|