From b4dbdd69324a85c9e65f3600fae0f7aea4637838 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Wed, 31 Dec 2025 15:11:33 -0600 Subject: [PATCH] test(auth): work on auth login and signup --- backend/src/auth/login.route.ts | 51 +++++++++++++++++++++++++++- backend/src/configs/scaler.config.ts | 32 ++++++++++++++--- backend/src/db/schema/auth.schema.ts | 1 - backend/src/utils/auth.utils.ts | 27 +++++++++++---- 4 files changed, 98 insertions(+), 13 deletions(-) diff --git a/backend/src/auth/login.route.ts b/backend/src/auth/login.route.ts index 6c6a5cb..5edfb32 100644 --- a/backend/src/auth/login.route.ts +++ b/backend/src/auth/login.route.ts @@ -8,6 +8,32 @@ import { user } from "../db/schema/auth.schema.js"; import { auth } from "../utils/auth.utils.js"; import { apiReturn } from "../utils/returnHelper.utils.js"; +// interface EmailLoginRequest { +// email: string; +// password: string; +// } + +// interface LoginResponse { +// redirect: boolean; +// token: string; +// user: { +// name: string; +// email: string; +// emailVerified: boolean; +// image: string | null; +// createdAt: string; +// updatedAt: string; +// role: string; +// banned: boolean; +// banReason: string | null; +// banExpires: string | null; +// username: string; +// displayUsername: string; +// lastLogin: string; +// id: string; +// }; +// } + const base = { password: z.string().min(8, "Password must be at least 8 characters"), }; @@ -28,7 +54,7 @@ const signin = z.union([ const r = Router(); r.post("/", async (req, res) => { - let login: unknown = []; + let login: unknown; try { const validated = signin.parse(req.body); if ("email" in validated) { @@ -69,6 +95,19 @@ r.post("/", async (req, res) => { }); } + // make sure we update the lastLogin + // if (login?.user?.id) { + // const updated = await db + // .update(user) + // .set({ lastLogin: sql`NOW()` }) + // .where(eq(user.id, login.user.id)) + // .returning({ lastLogin: user.lastLogin }); + + // const lastLoginTimestamp = updated[0]?.lastLogin; + // console.log("Updated lastLogin:", lastLoginTimestamp); + // } else + // console.warn("User ID unavailable — skipping lastLogin update"); + return apiReturn(res, { success: true, level: "info", //connect.success ? "info" : "error", @@ -108,6 +147,16 @@ r.post("/", async (req, res) => { status: 400, //connect.success ? 200 : 400, }); } + + return apiReturn(res, { + success: false, + level: "error", + module: "routes", + subModule: "auth", + message: "System Error", + data: [err], + status: 400, + }); } }); diff --git a/backend/src/configs/scaler.config.ts b/backend/src/configs/scaler.config.ts index 1e57849..bd0614c 100644 --- a/backend/src/configs/scaler.config.ts +++ b/backend/src/configs/scaler.config.ts @@ -38,6 +38,17 @@ export const openApiBase: OpenAPIV3_1.Document = { scheme: "bearer", bearerFormat: "JWT", }, + ApiKeyAuth: { + type: "apiKey", + description: "API key required for authentication", + name: "api_key", + in: "header", + }, + basicAuth: { + type: "http", + scheme: "basic", + description: "Basic authentication using username and password", + }, }, // schemas: { // Error: { @@ -47,12 +58,24 @@ export const openApiBase: OpenAPIV3_1.Document = { // message: { type: "string" }, // }, // }, - // }, + // },. }, + tags: [ - // { name: "Health", description: "Health check endpoints" }, - // { name: "Printing", description: "Label printing operations" }, - // { name: "Silo", description: "Silo management" }, + { + name: "Auth", + description: + "Authentication section where you get and create users and api keys", + }, + { + name: "System", + description: "All system endpoints that will be available to run", + }, + { + name: "Datamart", + description: + "All Special queries to run based on there names.\n Refer to the docs to see all possible queries that can be ran here, you can also run the getQueries to see available.", + }, // { name: "TMS", description: "TMS integration" }, ], paths: {}, // Will be populated @@ -96,6 +119,7 @@ export const setupApiDocsRoutes = (baseUrl: string, app: Express) => { targetKey: "node", clientKey: "axios", }, + documentDownloadType: "json", hideClientButton: true, hiddenClients: { diff --git a/backend/src/db/schema/auth.schema.ts b/backend/src/db/schema/auth.schema.ts index 4c67171..9210462 100644 --- a/backend/src/db/schema/auth.schema.ts +++ b/backend/src/db/schema/auth.schema.ts @@ -25,7 +25,6 @@ export const user = pgTable("user", { banExpires: timestamp("ban_expires"), username: text("username").unique(), displayUsername: text("display_username"), - lastLogin: timestamp("last_login").defaultNow(), }); export const session = pgTable( diff --git a/backend/src/utils/auth.utils.ts b/backend/src/utils/auth.utils.ts index c445ce2..3606af6 100644 --- a/backend/src/utils/auth.utils.ts +++ b/backend/src/utils/auth.utils.ts @@ -3,8 +3,10 @@ import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { admin, apiKey, + createAuthMiddleware, customSession, jwt, + lastLoginMethod, username, } from "better-auth/plugins"; import { eq } from "drizzle-orm"; @@ -38,7 +40,7 @@ export const auth = betterAuth({ }, lastLogin: { type: "date", - required: false, + required: true, input: false, }, }, @@ -47,6 +49,7 @@ export const auth = betterAuth({ jwt({ jwt: { expirationTime: "1h" } }), apiKey(), admin(), + lastLoginMethod(), username({ minUsernameLength: 5, usernameValidator: (username) => { @@ -119,12 +122,22 @@ export const auth = betterAuth({ secure: false, httpOnly: true, }, + hooks: { + after: createAuthMiddleware(async (ctx) => { + if (ctx.path.startsWith("/login")) { + const newSession = ctx.context.newSession; + if (newSession) { + // something here later + } + } + }), + }, events: { - async onSignInSuccess({ user }: { user: User }) { - await db - .update(rawSchema.user) - .set({ lastLogin: new Date() }) - .where(eq(schema.user.id, user.id)); - }, + // async onSignInSuccess({ user }: { user: User }) { + // await db + // .update(rawSchema.user) + // .set({ lastLogin: new Date() }) + // .where(eq(schema.user.id, user.id)); + // }, }, });