apps/api/src/auth implements the sender authentication foundation: email + password
signup/login, bcrypt password hashing, and a JWT session carried in an httpOnly cookie.
POST /auth/register—{ name, email, password }(password ≥ 8 chars) → creates the user, sets the session cookie, returns the userPOST /auth/login—{ email, password }→ verifies credentials, sets the session cookie, returns the userPOST /auth/logout— clears the session cookieGET /auth/me— returns the current session's user, or401if unauthenticated
The session cookie (session) is httpOnly, sameSite=lax, and secure in production. It is
verified on every request by attachSession middleware, which populates req.user when a
valid session is present; requireAuth rejects unauthenticated requests with 401.
Set JWT_SECRET in apps/api/.env.
apps/web/lib/auth-client.ts wraps the API client for login, register, logout, and me.
The login and register pages under apps/web/app/[locale] post to those endpoints, and
apps/web/app/[locale]/dashboard is a client-gated page that redirects to /login when
GET /auth/me returns no user.
This is the foundation contributors build the rest of the product against. New protected
routes on the API should use requireAuth; new protected pages on the web should follow the
DashboardGate pattern (check authClient.me(), redirect if absent).