fix(auth): found some bugs in the jwt token
This commit is contained in:
@@ -12,7 +12,7 @@ post {
|
|||||||
|
|
||||||
body:json {
|
body:json {
|
||||||
{
|
{
|
||||||
"username": "admin",
|
"username": "adm_matthes",
|
||||||
"password": "password123"
|
"password": "nova0511"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
10
globals.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
declare global {
|
||||||
|
namespace NodeJS {
|
||||||
|
interface ProcessEnv {
|
||||||
|
JWT_SECRET: string;
|
||||||
|
JWT_EXPIRES: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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}};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
10
server/src/services/auth/utils/checkPassword.ts
Normal file
10
server/src/services/auth/utils/checkPassword.ts
Normal 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;
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user