feat(web): add iron-session wrapper (web/lib/auth.ts)
This commit is contained in:
parent
f2facb200f
commit
a8751b6731
61
web/lib/auth.ts
Normal file
61
web/lib/auth.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import "server-only";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { sealData, unsealData } from "iron-session";
|
||||||
|
|
||||||
|
const COOKIE_NAME = "cm_auth";
|
||||||
|
const COOKIE_TTL_SECONDS = 30 * 24 * 60 * 60;
|
||||||
|
|
||||||
|
export type Session = {
|
||||||
|
username: string;
|
||||||
|
authenticatedAt: number;
|
||||||
|
pendingChallenge?: {
|
||||||
|
kind: "register" | "authenticate";
|
||||||
|
challenge: string;
|
||||||
|
expiresAt: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function secret(): string {
|
||||||
|
const s = process.env.CM_AUTH_SECRET;
|
||||||
|
if (!s || s.length < 32) {
|
||||||
|
throw new Error("CM_AUTH_SECRET missing or shorter than 32 chars");
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSession(): Promise<Session | null> {
|
||||||
|
const jar = await cookies();
|
||||||
|
const raw = jar.get(COOKIE_NAME)?.value;
|
||||||
|
if (!raw) return null;
|
||||||
|
try {
|
||||||
|
return await unsealData<Session>(raw, { password: secret() });
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setSession(session: Session): Promise<void> {
|
||||||
|
const sealed = await sealData(session, {
|
||||||
|
password: secret(),
|
||||||
|
ttl: COOKIE_TTL_SECONDS,
|
||||||
|
});
|
||||||
|
const jar = await cookies();
|
||||||
|
jar.set(COOKIE_NAME, sealed, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: process.env.NODE_ENV === "production",
|
||||||
|
sameSite: "lax",
|
||||||
|
path: "/",
|
||||||
|
maxAge: COOKIE_TTL_SECONDS,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function clearSession(): Promise<void> {
|
||||||
|
const jar = await cookies();
|
||||||
|
jar.delete(COOKIE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function requireSession(): Promise<Session> {
|
||||||
|
const s = await getSession();
|
||||||
|
if (!s) throw new Error("Unauthenticated");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user