Hey I am trying to make a simple auth login system using mongodb and passport.js, the signup works, the problem is with the login. I have searched the world wide web for an answer but can’t seem to find anything that fits my problem.
When trying to login with correct credentials I get this error message =>
Login.jsx =>
=> import { useState } from "react";
const Login = () => {
const [error, setError] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [data, setData] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await fetch("http://localhost:3000/auth/login", {
method: "POST",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
password: password,
}),
});
console.log("Response from server:", response);
if (response.ok) {
const data = await response.json();
console.log("Login successful");
} else {
const errorData = await response.json();
console.log("Login failed:", error, errorData)
}
} catch (error) {
console.error("Login error:", error);
setError("An error occurred")
}
}
return (
<form method="post" onSubmit={handleSubmit}>
<div id="create-account" className="flex flex-col items-center pt-12">
<div id="signup-text" className="pr-24">
<div id="signup-text" className="flex items-center">
<h1 className="font-semibold text-2xl">Login</h1>
<span className="text-2xl ml-2">đ</span>
</div>
<h2 className="">Enter your details below to login</h2>
</div>
<div id="signup-container" className="pr-2">
<div id="username" className="flex pt-2 space-y-3">
<input
type="username"
onChange={(e) => setUsername(e.target.value)}
id="email-user"
className="border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-80 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="Email or Username"
required
/>
</div>
<div id="password" className="flex items-center pt-2">
<input
type="password"
id="pass"
onChange={(e) => setPassword(e.target.value)}
className="border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-80 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="Password"
required
/>
</div>
<button
type="submit"
className="mt-2 text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700">Login</button>
</div>
<div id="or" className="flex items-center pt-6">
<hr className="flex-grow border-t border-gray-400" />
<h2 className="px-4">Or</h2>
<hr className="flex-grow border-t border-black-400" />
</div>
</div>
</form>
)
};
export default Login;
I also get this error from my server =>
Server.js =>
import express from "express";
import mongoose from "mongoose";
import UserModel from "./database/models/user.js";
import mongoConnection from "./database/index.js";
import cors from "cors";
import bodyParser from "body-parser";
import session from "express-session";
import bcrypt from "bcrypt";
import passport from "passport";
import passportConfig from "./config/passport-config.js";
import jwt from "jsonwebtoken";
import { Strategy } from "passport-local";
const app = express();
const PORT = 3000;
// Middleware ----------------------
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// making sure requests from the client side work
app.use(cors({
origin: "http://localhost:5173",
credentials: true,
}));
// session cookies
app.use(
session({
secret: "secretcode",
resave: true,
saveUninitialized: true
})
);
// ---- end of middleware
// signup
app.post("/user", async (req, res) => {
try {
// check if user or email already exists
const existingUser = await UserModel.findOne({ username: req.body.username });
const existingEmail = await UserModel.findOne({ email: req.body.email });
if (existingUser) {
return res.status(400).send("Username already exists");
} if (existingEmail) {
return res.status(400).send("Email already exists");
}
// hash password before save
const hashedPassword = await bcrypt.hash(req.body.password, 10);
const user = new UserModel({
username: req.body.username,
email: req.body.email,
password: hashedPassword,
});
// saving users to db/mongo
await user.save();
res.send(user);
console.log("saved user: ", user)
} catch (error) {
console.error(error);
res.status(500).send(error);
}
});
passportConfig(passport);
// login
app.post("/auth/login", (req, res, next) => {
console.log("Recieved login request:", req.body);
passport.authenticate("login", (err, user) => {
if (err) throw err;
console.log("User found in the db:", user);
if (!user) {
res.status(401).json({ message: "No user exists" })
}
else {
req.logIn(user, (err) => {
if (err) throw err;
res.send("Successfully Authenticated");
console.log(req.user);
});
}
})(req, res, next);
});
// starting server
app.listen(PORT, function(err) {
if (err) {
console.log("server could not start", err)
} else {
console.log("Server listening on Port:", PORT)
}
})
User.js =>
import { Schema, model } from "mongoose";
import bcrypt from "bcrypt";
// defining schema
const userSchema = new Schema({
username: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
// comparing password, if true match
userSchema.methods.matchPassword = async function (password) {
try {
return await bcrypt.compare(password, this.password);
} catch (error) {
console.error(error);
}
}
const UserModel = model("User", userSchema);
export default UserModel;
Passport-config.js =>
import passport from "passport";
import UserModel from "../database/models/user.js";
import bcrypt from "bcrypt";
import { Strategy as LocalStrategy } from "passport-local";
export default (passport) => {
// signup stratergy
passport.use(
"local-signup",
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
// Check if user already exists
const userExists = await UserModel.findOne({ email: email });
if (userExists) {
return done(null, false);
}
// Create a new user with the provided data
const user = await UserModel.create({ email, password });
return done(null, user);
} catch (error) {
return done(error);
}
}
)
);
// login stratergy
passport.use(
"login",
new LocalStrategy(
{
usernameField: "username",
passwordField: "password",
},
async (username, password, done) => {
try {
const user = await UserModel.findOne({ username: username });
if (!user) {
return done(null, false, { message: "User not found" });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return done(null, false, { message: "Invalid password" });
}
// If passwords match, return the user
return done(null, user);
} catch (error) {
console.log(error);
return done(error, false);
}
}
)
);
};
passport.serializeUser((user, done) => {
done(null, user.id)
});
passport.deserializeUser(async (id, done) => {
try {
const user = await UserModel.findById(id);
done(null, user);
} catch (err) {
done(err);
}
});
Would greatly appreciate any help as I have been stuck on this for a while now!
2
Answers
The issue was as phil described. My
Was not the same as the code being sent in the client.
In relation to your cors issue, first open it up to all origins to test if that works for you. You can do that by
In relation to the user found in db:false. it could be one of many things
To list a few:
Password hash comparison: Verify the password passed in the login route is being compared correctly
DB Query: Check what is return from the
User.findOne({…})
Tip:
In the deserializeUser function, you have a typo. Replace await
to correctly retrieve the user by ID.