fix(auth): found some bugs in the jwt token

This commit is contained in:
2025-02-21 21:54:26 -06:00
parent 026583815c
commit f320118880
11 changed files with 149 additions and 96 deletions

View File

@@ -12,7 +12,7 @@ post {
body:json { body:json {
{ {
"username": "admin", "username": "adm_matthes",
"password": "password123" "password": "nova0511"
} }
} }

View File

@@ -12,9 +12,8 @@ post {
body:json { body:json {
{ {
"username":"matthes02", "username": "adm_matthes",
"email": "blake@alpla.com", "email":"blake@alpla.com",
"password": "Vsd!134" "password": "nNova0511!"
} }
} }

View File

@@ -10,7 +10,7 @@ interface LstCardProps {
export function LstCard({children, className = "", style = {}}: LstCardProps) { export function LstCard({children, className = "", style = {}}: LstCardProps) {
return ( return (
<div className="m-auto"> <div className="m-auto">
<Card className={`border-solid border-2 border-[#00659c] ${className}`} style={style}> <Card className={`border-solid border-1 border-[#00659c] ${className}`} style={style}>
{children} {children}
</Card> </Card>
</div> </div>

10
globals.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
JWT_SECRET: string;
JWT_EXPIRES: string;
}
}
}
export {};

View File

@@ -26,6 +26,7 @@
"@hono/zod-openapi": "^0.18.4", "@hono/zod-openapi": "^0.18.4",
"@scalar/hono-api-reference": "^0.5.175", "@scalar/hono-api-reference": "^0.5.175",
"@types/bun": "^1.2.2", "@types/bun": "^1.2.2",
"@types/jsonwebtoken": "^9.0.8",
"axios": "^1.7.9", "axios": "^1.7.9",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"compression": "^1.8.0", "compression": "^1.8.0",

View File

@@ -1,28 +1,39 @@
import {sign, verify} from "jsonwebtoken"; import {sign, verify} from "jsonwebtoken";
import {db} from "../../../../database/dbClient";
import {users} from "../../../../database/schema/users";
import {eq} from "drizzle-orm";
import {checkPassword} from "../utils/checkPassword";
/** /**
* Authenticate a user and return a JWT. * Authenticate a user and return a JWT.
*/ */
const fakeUsers = [ export async function login(
{id: 1, username: "admin", password: "password123", role: "admin"},
{id: 2, username: "user", password: "pass", role: "user"},
{id: 3, username: "user2", password: "password123", role: "user"},
];
export function login(
username: string, username: string,
password: string password: string
): {token: string; user: {id: number; username: string; role: string}} { ): Promise<{token: string; user: {user_id: string; username: string}}> {
const user = fakeUsers.find((u) => u.username === username && u.password === password); const user = await db.select().from(users).where(eq(users.username, username));
if (!user) {
throw new Error("Invalid credentials"); if (user.length === 0) {
throw new Error("Invalid or Missing user");
}
// check the password
const checkedPass = await checkPassword(password, user[0]?.password);
console.log(checkedPass);
if (!checkedPass) {
throw new Error("Invalid Password");
} }
// Create a JWT // Create a JWT
const token = sign({user}, process.env.JWT_SECRET, { const secret: string = process.env.JWT_SECRET! || "bnghsjhsd";
expiresIn: process.env.JWT_EXPIRES, const expiresIn: string = process.env.JWT_EXPIRES! || "1h";
});
return {token, user: {id: user?.id, username: user.username, role: user.role}}; const userData = {
user_id: user[0].user_id,
username: user[0].username,
email: user[0].email,
};
const token = sign({user: userData}, secret, {expiresIn: 60 * 60});
return {token, user: {user_id: user[0].user_id, username: user[0].username}};
} }

View File

@@ -3,9 +3,13 @@ import {sign, verify} from "jsonwebtoken";
/** /**
* Verify a JWT and return the decoded payload. * Verify a JWT and return the decoded payload.
*/ */
const secret: string = process.env.JWT_SECRET! || "bnghsjhsd";
const expiresIn: string = process.env.JWT_EXPIRES! || "1h";
export function verifyToken(token: string): {userId: number} { export function verifyToken(token: string): {userId: number} {
try { try {
const payload = verify(token, process.env.JWT_SECRET) as {userId: number}; const payload = verify(token, secret) as {userId: number};
return payload; return payload;
} catch (err) { } catch (err) {
throw new Error("Invalid token"); throw new Error("Invalid token");

View File

@@ -65,7 +65,7 @@ const route = createRoute({
app.openapi(route, async (c) => { app.openapi(route, async (c) => {
const {username, password, email} = await c.req.json(); const {username, password, email} = await c.req.json();
if (!username || !password || !email) { if (!username || !password) {
return c.json( return c.json(
{ {
success: false, success: false,
@@ -75,8 +75,9 @@ app.openapi(route, async (c) => {
); );
} }
const {token, user} = await login(username.toLowerCase(), password);
try { try {
const {token, user} = login(username.toLowerCase(), password); const {token, user} = await login(username.toLowerCase(), password);
// Set the JWT as an HTTP-only cookie // Set the JWT as an HTTP-only cookie
//c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`); //c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
@@ -87,29 +88,4 @@ app.openapi(route, async (c) => {
} }
}); });
/*
let body = {username: "", password: "", error: ""};
try {
body = await c.req.json();
} catch (error) {
return c.json({success: false, message: "Username and password required"}, 400);
}
if (!body?.username || !body?.password) {
return c.json({message: "Username and password required"}, 400);
}
try {
const {token, user} = login(body?.username, body?.password);
// Set the JWT as an HTTP-only cookie
c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
return c.json({message: "Login successful", user});
} catch (err) {
// console.log(err);
return c.json({message: err}, 401);
}
*/
export default app; export default app;

View File

@@ -3,55 +3,97 @@ import {verify} from "hono/jwt";
const session = new OpenAPIHono(); const session = new OpenAPIHono();
const tags = ["Auth"]; const tags = ["Auth"];
const JWT_SECRET = process.env.JWT_SECRET; const JWT_SECRET = process.env.JWT_SECRET!;
const route = createRoute({ const UserSchema = z.object({
tags: ["Auth"], username: z
summary: "Checks a user session based on there token", .string()
description: "Can post there via Authentiaction header or cookies", .regex(/^[a-zA-Z0-9_]{3,30}$/)
method: "get", .openapi({example: "smith034"}),
path: "/", email: z.string().email().openapi({example: "smith@example.com"}),
request: {body: {content: {"application/json": {schema: {username: "", password: ""}}}}}, password: z
responses: { .string()
200: { .min(6, {message: "Passwords must be longer than 3 characters"})
content: { .regex(/[A-Z]/, {message: "Password must contain at least one uppercase letter"})
"application/json": { .regex(/[\W_]/, {message: "Password must contain at least one special character"})
schema: {session: ""}, .openapi({example: "Password1!"}),
},
},
description: "Login successful",
},
401: {
content: {
"application/json": {
schema: {message: ""},
},
},
description: "Error of why you were not logged in.",
},
},
}); });
session.openapi(route, async (c) => {
const authHeader = c.req.header("Authorization");
if (authHeader?.includes("Basic")) { session.openapi(
// createRoute({
return c.json({message: "You are a Basic user! Please login to get a token"}, 401); tags,
summary: "Checks a user session based on there token",
description: "Can post there via Authentiaction header or cookies",
method: "get",
path: "/",
// request: {
// body: {
// content: {
// "application/json": {schema: UserSchema},
// },
// },
// },
responses: {
200: {
content: {
"application/json": {
schema: z.object({
data: z.object({
token: z.string().openapi({example: "sdkjhgsldkvhdakl;jvhs;adkjfhvds.kvnsad;ovhads"}),
// user: z.object({
// user_id: z.string().openapi({example: "04316c86-f086-4cc6-b3d4-cca164a26f3f"}),
// username: z.string().openapi({example: "smith"}),
// email: z.string().openapi({example: "smith@example.com"}).optional(),
// }),
}),
}),
},
},
description: "Login successful",
},
401: {
content: {
"application/json": {
schema: z.object({
message: z.string().openapi({example: "Unathenticated"}),
}),
},
},
description: "Error of why you were not logged in.",
},
},
}),
async (c) => {
const authHeader = c.req.header("Authorization");
if (authHeader?.includes("Basic")) {
return c.json({message: "You are a Basic user! Please login to get a token"}, 401);
}
if (!authHeader) {
return c.json({message: "Unauthorized"}, 401);
}
const token = authHeader?.split("Bearer ")[1] || "";
try {
const payload = await verify(token, process.env.JWT_SECRET!);
return c.json({data: {token: token, user: payload.user}}, 200);
} catch (error) {}
return c.json({data: {token: "tsfds"}}, 200);
} }
);
if (!authHeader) { // const token = authHeader?.split("Bearer ")[1] || "";
return c.json({error: "Unauthorized"}, 401);
}
const token = authHeader?.split("Bearer ")[1] || ""; // try {
// const payload = await verify(token, process.env.JWT_SECRET!);
try { // //console.log(payload);
const payload = await verify(token, JWT_SECRET); // //return c.json({data: {token, user: payload.user}}, 200);
//console.log(payload); // return c.json({message: "something"});
return c.json({data: {token, user: payload.user}}); // } catch (err) {
} catch (err) { // return c.json({error: "Invalid or expired token"}, 401);
return c.json({error: "Invalid or expired token"}, 401); // }
} // });
});
export default session; export default session;

View File

@@ -0,0 +1,10 @@
import bcrypt from "bcrypt";
export const checkPassword = async (currentPassword: string, dbPassword: string) => {
// encypt password
const pass: string | undefined = process.env.SECRET;
const checked = bcrypt.compareSync(pass + currentPassword, dbPassword);
return checked;
};

View File

@@ -8,9 +8,9 @@ export const createPassword = async (password: string) => {
if (!pass || !salt) { if (!pass || !salt) {
pass = "error"; pass = "error";
} else { } else {
pass = bcrypt.hashSync(process.env.SECRET + password, parseInt(salt)); pass = bcrypt.hashSync(pass + password, parseInt(salt));
pass = btoa(pass); // pass = btoa(pass);
} }
return pass; return pass;