Implement auth as source of truth on server and protect routes. Integrate with portal

This commit is contained in:
Dominic Ferrando
2026-06-30 23:46:35 -04:00
parent 235c072421
commit f5fb64e467
9 changed files with 83 additions and 42 deletions
+1
View File
@@ -17,6 +17,7 @@
"@blade-and-brawn/calculator": "workspace:*",
"@blade-and-brawn/commerce": "workspace:*",
"@blade-and-brawn/domain": "workspace:*",
"@elysia/jwt": "^1.4.2",
"@elysia/server-timing": "^1.4.1",
"@elysiajs/cors": "^1.4.2",
"elysia": "^1.4.29",
+2
View File
@@ -17,6 +17,8 @@ export const env = {
WEBFLOW_COLLECTION_ID: requireEnv("WEBFLOW_COLLECTION_ID"),
WEBFLOW_AUTH: requireEnv("WEBFLOW_AUTH"),
WEBFLOW_WEBHOOK_SECRET: requireEnv("WEBFLOW_WEBHOOK_SECRET"),
AUTH_SECRET: requireEnv("AUTH_SECRET"),
ADMIN_PASSWORD: requireEnv("ADMIN_PASSWORD"),
NODE_ENV: optionEnv("NODE_ENV", "development"),
LOG_LEVEL: optionEnv("LOG_LEVEL", "info"),
};
+28 -5
View File
@@ -24,6 +24,7 @@ import z from "zod";
import pino from "pino";
import { env } from "./env";
import serverTiming from "@elysia/server-timing";
import jwt from "@elysia/jwt";
const log = pino({
level: env.LOG_LEVEL,
@@ -75,7 +76,7 @@ export const app = new Elysia()
"http://dev.portal.bladeandbrawn.com/"
],
}),
)
).use(jwt({ name: "jwt", secret: env.AUTH_SECRET }))
.error({
PrintfulError,
@@ -116,8 +117,29 @@ export const app = new Elysia()
.get("/", () => ({ status: "ok" }))
.get("/health", () => ({ status: "ok" }))
// CALCULATOR
// AUTHENTICATION
.post("/auth/login", async ({ jwt, body, cookie: { auth } }) => {
if (body.password !== env.ADMIN_PASSWORD) throw status(401, "Invalid credentials");
auth.set({
value: await jwt.sign({ id: "admin", exp: "7d" }),
path: "/",
maxAge: 60 * 60 * 24 * 7,
sameSite: "lax",
httpOnly: true,
secure: env.NODE_ENV === "production",
domain: env.NODE_ENV === "production" ?
".bladeandbrawn.com" :
undefined
});
}, {
body: z.object({
password: z.coerce.string()
}),
cookie: t.Cookie({ auth: t.Optional(t.String()) })
})
// CALCULATOR
.post("/calculate", async ({ body }) => {
return {
levels: levelCalculator.calculate(body.player, body.activityPerformances),
@@ -130,11 +152,12 @@ export const app = new Elysia()
})
// COMMERCE
// TODO: protect with api key/token
.group("/products", (app) =>
app
.onBeforeHandle(({ }) => {
// authenticate cookie
.guard({ cookie: t.Cookie({ auth: t.Optional(t.String()) }) })
.onBeforeHandle(async ({ jwt, cookie: { auth } }) => {
const token = auth.value && await jwt.verify(auth.value);
if (!token) throw status(401, "Unauthorized");
})
.group("/sync", (app) =>
app