diff --git a/backend/.env.example b/backend/.env.example
deleted file mode 100644
index da4e603..0000000
--- a/backend/.env.example
+++ /dev/null
@@ -1,12 +0,0 @@
-MONGO_URI=
-EMAIL_USER=your_gmail
-PORT=3000
-EMAIL_PASS=your_16_digit_pass
-JWT_SECRET=secret
-GOOGLE_CLIENT_ID=your_google_client_id
-GOOGLE_CLIENT_SECRET=your_google_client_secret
-FRONTEND_URL=your_frontend_url
-CALLBACK_URL=http://localhost:3000/auth/google/callback
-PROD_CALLBACK_URL=https://play-cafe.vercel.app/auth/google/callback
-NODE_ENV=development
-SECRET_KEY=your_secret_key
diff --git a/backend/controller/customer.controller.js b/backend/controller/customer.controller.js
index 92242da..3f494f2 100644
--- a/backend/controller/customer.controller.js
+++ b/backend/controller/customer.controller.js
@@ -87,6 +87,7 @@ async function loginCustomer(req, res) {
const customerLoginSchema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(6, "Password must be at least 6 characters long"),
+ rememberMe: z.boolean().optional(),
});
const validation = customerLoginSchema.safeParse(req.body);
@@ -95,7 +96,8 @@ async function loginCustomer(req, res) {
}
try {
- const customer = await Customer.findOne({ email: req.body.email });
+ const { email, password, rememberMe } = req.body;
+ const customer = await Customer.findOne({ email });
if (!customer) {
return res.status(401).json({ error: "Invalid email or password" });
@@ -104,25 +106,27 @@ async function loginCustomer(req, res) {
return res.status(403).json({ error: "Account not verified. Please verify your email." });
}
- const validPassword = await bcrypt.compare(req.body.password, customer.password);
+ const validPassword = await bcrypt.compare(password, customer.password);
if (!validPassword) {
return res.status(401).json({ error: "Invalid email or password" });
}
const payload = {
- sub: customer._id, // Use `sub` as this is a standard JWT claim for subject (user ID)
+ sub: customer._id,
name: customer.name,
role: "customer",
email: customer.email,
};
- const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: "1h" });
+ const token = jwt.sign(payload, process.env.JWT_SECRET, {
+ expiresIn: rememberMe ? "7d" : "1h", // Set token expiry based on rememberMe option
+ });
res.cookie("authToken", token, {
- maxAge: 60 * 60 * 1000, // 1 hour
- httpOnly: false, // Set to false if you need access on the frontend
- secure: process.env.NODE_ENV === "production", // Set `secure: true` only in production with HTTPS
- sameSite: "strict", // Use `strict` to avoid CSRF in most cases
+ maxAge: rememberMe ? 7 * 24 * 60 * 60 * 1000 : 60 * 60 * 1000, // 7 days or 1 hour
+ httpOnly: true,
+ secure: process.env.NODE_ENV === "production",
+ sameSite: "strict",
});
return res.json({
@@ -142,6 +146,7 @@ async function loginCustomer(req, res) {
}
+
async function resetPassword(req, res) {
const customerResetPasswordSchema = z.object({
email: z.string().email("Invalid email address"),
diff --git a/frontend/src/components/Pages/Login.jsx b/frontend/src/components/Pages/Login.jsx
index d652959..e3e5c1a 100644
--- a/frontend/src/components/Pages/Login.jsx
+++ b/frontend/src/components/Pages/Login.jsx
@@ -3,8 +3,7 @@ import photo from '../../assets/login.png';
import { Link, useNavigate } from 'react-router-dom';
import { message } from 'antd';
import Cookies from 'js-cookie';
-import { FaEye } from 'react-icons/fa';
-import { FaEyeSlash } from 'react-icons/fa6';
+import { FaEye, FaEyeSlash } from 'react-icons/fa';
const Login = () => {
const API_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3000';
@@ -12,6 +11,7 @@ const Login = () => {
const [hidden, setHidden] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
+ const [rememberMe, setRememberMe] = useState(false); // New state for Remember Me
const navigate = useNavigate();
const handleChange = (e) => {
@@ -29,13 +29,14 @@ const Login = () => {
headers: {
'Content-Type': 'application/json',
},
- body: JSON.stringify(data),
+ body: JSON.stringify({ ...data, rememberMe }), // Include rememberMe in the body
});
const result = await response.json();
if (!response.ok) throw new Error(result.message || 'Login failed');
+ // Set cookie expiration based on Remember Me option
Cookies.set('authToken', result.token, {
- expires: 1 / 24, // 1 hour
+ expires: rememberMe ? 7 : 1 / 24, // 7 days if Remember Me is checked, 1 hour otherwise
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
});
@@ -101,6 +102,15 @@ const Login = () => {
+
+