feat: authentication

This commit is contained in:
Nicolas Meienberger
2025-10-02 18:47:25 +02:00
parent 7f79fd7628
commit 1e7530cc09
11 changed files with 642 additions and 6 deletions

View File

@@ -0,0 +1,79 @@
import { arktypeValidator } from "@hono/arktype-validator";
import { Hono } from "hono";
import { deleteCookie, getCookie, setCookie } from "hono/cookie";
import { getMeDto, loginBodySchema, loginDto, logoutDto, registerBodySchema, registerDto } from "./auth.dto";
import { authService } from "./auth.service";
const COOKIE_NAME = "session_id";
const COOKIE_OPTIONS = {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax" as const,
path: "/",
};
export const authController = new Hono()
.post("/register", registerDto, arktypeValidator("json", registerBodySchema), async (c) => {
const body = c.req.valid("json");
try {
const { user } = await authService.register(body.username, body.password);
return c.json(
{
message: "User registered successfully",
user: { id: user.id, username: user.username },
},
201,
);
} catch (error) {
return c.json({ message: error instanceof Error ? error.message : "Registration failed" }, 400);
}
})
.post("/login", loginDto, arktypeValidator("json", loginBodySchema), async (c) => {
const body = c.req.valid("json");
try {
const { sessionId, user, expiresAt } = await authService.login(body.username, body.password);
setCookie(c, COOKIE_NAME, sessionId, {
...COOKIE_OPTIONS,
expires: expiresAt,
});
return c.json({
message: "Login successful",
user: { id: user.id, username: user.username },
});
} catch (error) {
return c.json({ message: error instanceof Error ? error.message : "Login failed" }, 401);
}
})
.post("/logout", logoutDto, async (c) => {
const sessionId = getCookie(c, COOKIE_NAME);
if (sessionId) {
await authService.logout(sessionId);
deleteCookie(c, COOKIE_NAME, COOKIE_OPTIONS);
}
return c.json({ message: "Logout successful" });
})
.get("/me", getMeDto, async (c) => {
const sessionId = getCookie(c, COOKIE_NAME);
if (!sessionId) {
return c.json({ message: "Not authenticated" }, 401);
}
const session = await authService.verifySession(sessionId);
if (!session) {
deleteCookie(c, COOKIE_NAME, COOKIE_OPTIONS);
return c.json({ message: "Not authenticated" }, 401);
}
return c.json({
user: session.user,
});
});