fix: switch from httpOnly cookies to localStorage Bearer token auth
Some checks failed
Build & Release / build (push) Has been cancelled

Cookie-based auth was unreliable through Cloudflare/nginx proxy — cookie
was being sent for some requests but not others. Switch to returning JWT
in login response, storing in localStorage, and sending as Authorization
Bearer header on all API calls. Eliminates all cookie/SameSite/Secure
proxy issues.
This commit is contained in:
Ryan Moon
2026-04-03 18:09:23 -05:00
parent 74df8e8cb0
commit 38341aa0a9
3 changed files with 30 additions and 25 deletions

View File

@@ -17,16 +17,13 @@ import { customerRoutes } from "./routes/customers";
const app = Fastify({ logger: true });
await app.register(cookiePlugin);
await app.register(jwtPlugin, {
secret: config.jwtSecret,
cookie: { cookieName: "token", signed: false },
});
await app.register(jwtPlugin, { secret: config.jwtSecret });
app.decorate("authenticate", async function (req: any, reply: any) {
try {
await req.jwtVerify({ onlyCookie: true });
await req.jwtVerify();
} catch {
reply.status(401).send({ message: "Unauthorized" });
return reply.status(401).send({ message: "Unauthorized" });
}
});

View File

@@ -47,20 +47,10 @@ export async function authRoutes(app: FastifyInstance) {
}
const token = app.jwt.sign({ sub: user.id, username: user.username }, { expiresIn: "7d" });
reply.setCookie("token", token, {
httpOnly: true,
secure: true,
sameSite: "lax",
path: "/",
maxAge: 60 * 60 * 24 * 7,
});
return { username: user.username };
return { username: user.username, token };
});
app.post("/auth/logout", async (_req, reply) => {
reply.clearCookie("token", { path: "/" });
app.post("/auth/logout", async () => {
return { ok: true };
});