Implementing login with Prisma

Below is the source code of my api but I figure out that any one entering credentials when an entered email resemble that of the one in the database, the user is authenticated without checking the corresponding password, how can I fix this, as the stored password is hashed?
import { NextResponse,type NextRequest } from "next/server";
import prisma from "@/prisma/client";
import {Redis} from "@upstash/redis"


const redis = Redis.fromEnv();

export async function POST(req: NextRequest, res: NextResponse) {
try {
const body = await req.json();
const { email, password } = body;

console.time()

if (!email || !password) {
return new NextResponse("Email and password are required", { status: 400 });
}

const user = await prisma.user.findFirst({
where: {
email: email as string,
role: "ADMIN",
ustate:"NON_BLOCKED",
}, select: {
id: true,
email: true,
name: true,
image: true,
role:true
},
});

if (!user) {
return new NextResponse("User not found", { status: 404 });
}

const member = await redis.set("user",user)
console.log(member)

const response = {
message: "Authenticated!",
};

console.timeEnd()

return new Response(JSON.stringify(response), {
status: 200,
});


} catch (error) {
console.error("Error fetching user:", error);
return new NextResponse("Internal Error", { status: 500 });
}
}
import { NextResponse,type NextRequest } from "next/server";
import prisma from "@/prisma/client";
import {Redis} from "@upstash/redis"


const redis = Redis.fromEnv();

export async function POST(req: NextRequest, res: NextResponse) {
try {
const body = await req.json();
const { email, password } = body;

console.time()

if (!email || !password) {
return new NextResponse("Email and password are required", { status: 400 });
}

const user = await prisma.user.findFirst({
where: {
email: email as string,
role: "ADMIN",
ustate:"NON_BLOCKED",
}, select: {
id: true,
email: true,
name: true,
image: true,
role:true
},
});

if (!user) {
return new NextResponse("User not found", { status: 404 });
}

const member = await redis.set("user",user)
console.log(member)

const response = {
message: "Authenticated!",
};

console.timeEnd()

return new Response(JSON.stringify(response), {
status: 200,
});


} catch (error) {
console.error("Error fetching user:", error);
return new NextResponse("Internal Error", { status: 500 });
}
}
12 Replies
Christoph
Christoph15mo ago
You hash the input and compare it with your hash in your database. Modern hash algorithms come with special functions to compare the hash to a value. Reason being that configuration data and the salt is stored with the hash.
Revaycolizer
RevaycolizerOP15mo ago
I tried but didn't work for me as bycrpt produces different values
Christoph
Christoph15mo ago
How did you compare?
Revaycolizer
RevaycolizerOP15mo ago
import { NextResponse,type NextRequest } from "next/server";
import prisma from "@/prisma/client";
import {Redis} from "@upstash/redis"
import bcrypt from "bcrypt";


const redis = Redis.fromEnv();

export async function POST(req: NextRequest, res: NextResponse) {
try {
const body = await req.json();
const { email, password } = body;

console.time()

if (!email || !password) {
return new NextResponse("Email and password are required", { status: 400 });
}

const user = await prisma.user.findFirst({
where: {
email: email as string,
role: "ADMIN",
ustate:"NON_BLOCKED",
}, select: {
id: true,
email: true,
name: true,
image: true,
role:true,
hashedPassword:true
},
});

if (!user || !user.hashedPassword) {
return new NextResponse("User not found", { status: 404 });
}

const Password = await bcrypt.hash(password, 12);

console.log

const passwordMatch = await bcrypt.compare(Password, user.hashedPassword);

if (!passwordMatch) {
return new NextResponse("Invalid credentials", { status: 401 });
}

const member = await redis.set("user",user)
console.log(member)

const response = {
message: "Authenticated!",
};

console.timeEnd()

return new Response(JSON.stringify(response), {
status: 200,
});


} catch (error) {
console.error("Error fetching user:", error);
return new NextResponse("Internal Error", { status: 500 });
}
}

import { NextResponse,type NextRequest } from "next/server";
import prisma from "@/prisma/client";
import {Redis} from "@upstash/redis"
import bcrypt from "bcrypt";


const redis = Redis.fromEnv();

export async function POST(req: NextRequest, res: NextResponse) {
try {
const body = await req.json();
const { email, password } = body;

console.time()

if (!email || !password) {
return new NextResponse("Email and password are required", { status: 400 });
}

const user = await prisma.user.findFirst({
where: {
email: email as string,
role: "ADMIN",
ustate:"NON_BLOCKED",
}, select: {
id: true,
email: true,
name: true,
image: true,
role:true,
hashedPassword:true
},
});

if (!user || !user.hashedPassword) {
return new NextResponse("User not found", { status: 404 });
}

const Password = await bcrypt.hash(password, 12);

console.log

const passwordMatch = await bcrypt.compare(Password, user.hashedPassword);

if (!passwordMatch) {
return new NextResponse("Invalid credentials", { status: 401 });
}

const member = await redis.set("user",user)
console.log(member)

const response = {
message: "Authenticated!",
};

console.timeEnd()

return new Response(JSON.stringify(response), {
status: 200,
});


} catch (error) {
console.error("Error fetching user:", error);
return new NextResponse("Internal Error", { status: 500 });
}
}

Christoph
Christoph15mo ago
compare takes the plaintext password as an input, not a hash. You compare the input to the hash stored in the database. Btw. probably not the best idea to implement authentication yourself.
Revaycolizer
RevaycolizerOP15mo ago
I compared the hash As the user input is hashed then the hashed value is compared with the hashed Password in the database Then what is the best idea as I want to implement authentication which can be used in both platforms
Christoph
Christoph15mo ago
Yep, that's the mistake. Check the docs for bcrypt.compare. Should be self-explanatory.
Revaycolizer
RevaycolizerOP15mo ago
Thanks let me check it
Christoph
Christoph15mo ago
Use a service (Clerk, Firebase, Auth0, ...) or a library (NextAuth, Lucia, ...) Nothing wrong with implementing it yourself to understand it. But the deeper you go the more complex it gets.
Revaycolizer
RevaycolizerOP15mo ago
Next-auth only accessible in Nextjs I once used it but when tried consuming the API in for login in another frameworks it didn't work out
Christoph
Christoph15mo ago
NextAuth only offers a library for Next.js, true. Services usually offer libraries for multiple languages.
Revaycolizer
RevaycolizerOP15mo ago
@xchristoph the comparison works thanks
Want results from more Discord servers?
Add your server