fix(web): make session cookie secure flag conditional on production
Setting Secure on http://localhost cookies works in Chrome (localhost exception) but Firefox/Safari silently drop them, so dev users hit 'redirect to /login on every click' after a 'successful' login. Switch to secure: NODE_ENV === 'production'. Public deploy still gets Secure-only. Also swap the login footer copy from a CLI hint to 'Forget Password? Contact IT' — operator-friendly, doesn't leak the bootstrap mechanism on the public sign-in screen. Test updated to assert secure=true under prod NODE_ENV and a new test locks in secure=false in dev. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7ab51335a4
commit
ebbbdbdfb8
@ -79,6 +79,10 @@ function fd(fields: Record<string, string>): FormData {
|
|||||||
describe("loginAction", () => {
|
describe("loginAction", () => {
|
||||||
it("issues a session cookie when credentials are correct", async () => {
|
it("issues a session cookie when credentials are correct", async () => {
|
||||||
findUserMock.mockResolvedValue(ADMIN_ROW);
|
findUserMock.mockResolvedValue(ADMIN_ROW);
|
||||||
|
const prevEnv = process.env.NODE_ENV;
|
||||||
|
// @ts-expect-error - test override
|
||||||
|
process.env.NODE_ENV = "production";
|
||||||
|
try {
|
||||||
const r = await loginAction(fd({ username: "admin", password: "correct-horse" })).catch(
|
const r = await loginAction(fd({ username: "admin", password: "correct-horse" })).catch(
|
||||||
(e) => e,
|
(e) => e,
|
||||||
);
|
);
|
||||||
@ -94,6 +98,25 @@ describe("loginAction", () => {
|
|||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 30 * 86400,
|
maxAge: 30 * 86400,
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
// @ts-expect-error - test restore
|
||||||
|
process.env.NODE_ENV = prevEnv;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets secure=false on the cookie when NODE_ENV !== production", async () => {
|
||||||
|
findUserMock.mockResolvedValue(ADMIN_ROW);
|
||||||
|
const prevEnv = process.env.NODE_ENV;
|
||||||
|
// @ts-expect-error - test override
|
||||||
|
process.env.NODE_ENV = "development";
|
||||||
|
try {
|
||||||
|
await loginAction(fd({ username: "admin", password: "correct-horse" })).catch(() => {});
|
||||||
|
const [, , attrs] = cookiesSetMock.mock.calls[0]!;
|
||||||
|
expect(attrs).toMatchObject({ secure: false });
|
||||||
|
} finally {
|
||||||
|
// @ts-expect-error - test restore
|
||||||
|
process.env.NODE_ENV = prevEnv;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns ok:false on wrong password and does NOT set a cookie", async () => {
|
it("returns ok:false on wrong password and does NOT set a cookie", async () => {
|
||||||
|
|||||||
@ -98,9 +98,14 @@ export async function loginAction(formData: FormData): Promise<LoginResult> {
|
|||||||
secret,
|
secret,
|
||||||
);
|
);
|
||||||
const jar = await cookies();
|
const jar = await cookies();
|
||||||
|
// Secure: only require https in production. In dev we hit
|
||||||
|
// http://localhost:9000 directly, and Firefox/Safari silently drop
|
||||||
|
// Set-Cookie when Secure is set on http origins (Chrome has a
|
||||||
|
// localhost exception, others don't), which manifested as the
|
||||||
|
// session cookie never being persisted across requests.
|
||||||
jar.set(COOKIE_NAME, cookie, {
|
jar.set(COOKIE_NAME, cookie, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: true,
|
secure: process.env.NODE_ENV === "production",
|
||||||
sameSite: "lax",
|
sameSite: "lax",
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: DEFAULT_TTL_SECONDS,
|
maxAge: DEFAULT_TTL_SECONDS,
|
||||||
|
|||||||
@ -59,8 +59,7 @@ export function LoginFormClient({ next }: { next: string }) {
|
|||||||
Sign in
|
Sign in
|
||||||
</Button>
|
</Button>
|
||||||
<p className="text-xs text-muted-foreground text-center">
|
<p className="text-xs text-muted-foreground text-center">
|
||||||
First time? Run <code>./scripts/set-password.sh <username></code>{" "}
|
Forget Password? Contact IT
|
||||||
in your tools container.
|
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user