I am making a login route with jwt token and express. When I create an account, the password is hashed by bcrypt. When I log in, I need to compare them. I tried with simplest password but it didn’t work. So here is my try :
const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/User");
const { verifyAdmin } = require("../middleware/authMiddleware");
const router = express.Router();
router.post("/login", async (req, res) => {
const { username, password } = req.body;
try {
const user = await User.findOne({ username });
if (!user) {
return res.status(400).json({ message: "Invalid credentials" });
}
// Log the received and hashed passwords for debugging
console.log("Received password:", password);
console.log("Stored hashed password:", user.password);
const isMatch = await bcrypt.compare(password, user.password);
console.log("Password match result:", isMatch);
if (!isMatch) {
return res.status(400).json({ message: "Invalid credentials" });
}
const payload = {
user: {
id: user.id,
userType: user.userType,
},
};
jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: "1h" },
(err, token) => {
if (err) throw err;
res.json({ token, user });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
// Create User
router.post("/create", async (req, res) => {
const { name, username, password, userType, process } = req.body;
try {
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({
name,
username,
password: hashedPassword,
userType,
process: userType === "Process Department" ? process : undefined,
});
await newUser.save();
res.status(201).json({ message: "User created successfully" });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
module.exports = router;
The problem is, my route returns “Invalid credentials”.
Create user frontend –>
// src/redux/reducers/userSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import api from "../../api/axiosConfig";
export const createUser = createAsyncThunk(
"user/createUser",
async (userData, thunkAPI) => {
try {
const response = await api.post("/auth/create", userData
);
return response.data;
} catch (error) {
return thunkAPI.rejectWithValue(error.response.data.message);
}
}
);
const userSlice = createSlice({
name: "user",
initialState: {
isLoading: false,
success: false,
error: null,
},
reducers: {
resetState: (state) => {
state.isLoading = false;
state.success = false;
state.error = null;
},
},
extraReducers: (builder) => {
builder
.addCase(createUser.pending, (state) => {
state.isLoading = true;
state.success = false;
state.error = null;
})
.addCase(createUser.fulfilled, (state) => {
state.isLoading = false;
state.success = true;
state.error = null;
})
.addCase(createUser.rejected, (state, action) => {
state.isLoading = false;
state.success = false;
state.error = action.payload;
});
},
});
export const { resetState } = userSlice.actions;
export default userSlice.reducer;
Login frontend –>
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import api from "../../api/axiosConfig";
export const login = createAsyncThunk(
"auth/login",
async ({ username, password }, thunkAPI) => {
try {
const response = await api.post("/auth/login", {
username,
password,
});
return response.data;
} catch (error) {
return thunkAPI.rejectWithValue(error.response.data.message);
}
}
);
export const logout = createAsyncThunk("auth/logout", async (_, thunkAPI) => {
// perform any necessary cleanup here
return true;
});
const authSlice = createSlice({
name: "auth",
initialState: {
isLoading: false,
user: null,
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(login.pending, (state) => {
state.isLoading = true;
state.error = null;
})
.addCase(login.fulfilled, (state, action) => {
state.isLoading = false;
state.user = action.payload.user;
state.error = null;
})
.addCase(login.rejected, (state, action) => {
state.isLoading = false;
state.user = null;
state.error = action.payload;
})
.addCase(logout.fulfilled, (state) => {
state.user = null;
state.error = null;
});
},
});
export default authSlice.reducer;