Add basic login screen with form-based authentication
Adds /login route with HTML template that handles GET (show form) and POST (authenticate). On successful login, sets session cookie and redirects to /. Also adds framework support for redirects and cookies in route handlers. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
62
express/basic/login.ts
Normal file
62
express/basic/login.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { SESSION_COOKIE_NAME } from "../auth/token";
|
||||
import { tokenLifetimes } from "../auth/types";
|
||||
import { services } from "../services";
|
||||
import type { Call, Result, Route } from "../types";
|
||||
import { html, redirect, render } from "../util";
|
||||
|
||||
const loginHandler = async (call: Call): Promise<Result> => {
|
||||
if (call.method === "GET") {
|
||||
const c = await render("basic/login", {});
|
||||
return html(c);
|
||||
}
|
||||
|
||||
// POST - handle login
|
||||
const { email, password } = call.request.body;
|
||||
|
||||
if (!email || !password) {
|
||||
const c = await render("basic/login", {
|
||||
error: "Email and password are required",
|
||||
email,
|
||||
});
|
||||
return html(c);
|
||||
}
|
||||
|
||||
const result = await services.auth.login(email, password, "cookie", {
|
||||
userAgent: call.request.get("User-Agent"),
|
||||
ipAddress: call.request.ip,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
const c = await render("basic/login", {
|
||||
error: result.error,
|
||||
email,
|
||||
});
|
||||
return html(c);
|
||||
}
|
||||
|
||||
// Success - set cookie and redirect to home
|
||||
const redirectResult = redirect("/");
|
||||
redirectResult.cookies = [
|
||||
{
|
||||
name: SESSION_COOKIE_NAME,
|
||||
value: result.token,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
secure: false, // Set to true in production with HTTPS
|
||||
sameSite: "lax",
|
||||
maxAge: tokenLifetimes.session,
|
||||
path: "/",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return redirectResult;
|
||||
};
|
||||
|
||||
const loginRoute: Route = {
|
||||
path: "/login",
|
||||
methods: ["GET", "POST"],
|
||||
handler: loginHandler,
|
||||
};
|
||||
|
||||
export { loginRoute };
|
||||
@@ -1,18 +1,29 @@
|
||||
import { DateTime } from "ts-luxon";
|
||||
import type { Call, Result, Route } from "../types";
|
||||
import { html, render } from "../util";
|
||||
import { loginRoute } from "./login";
|
||||
|
||||
const routes: Record<string, Route> = {
|
||||
hello: {
|
||||
path: "/hello",
|
||||
methods: ["GET"],
|
||||
handler: async (call: Call): Promise<Result> => {
|
||||
handler: async (_call: Call): Promise<Result> => {
|
||||
const now = DateTime.now();
|
||||
const c = await render("basic/hello", { now });
|
||||
|
||||
return html(c);
|
||||
},
|
||||
},
|
||||
home: {
|
||||
path:'/',
|
||||
methods:['GET'],
|
||||
handler:async(_call:Call): Promise<Result> => {
|
||||
const c = await render('basic/home')
|
||||
|
||||
return html(c)
|
||||
}
|
||||
},
|
||||
login: loginRoute,
|
||||
};
|
||||
|
||||
export { routes };
|
||||
|
||||
Reference in New Issue
Block a user