Skip to content

Commit

Permalink
fix(backend): resolve issues in auth API endpoints, JWT strategy, and…
Browse files Browse the repository at this point in the history
… MongoDB connection (#873)

### Backend Fixes and Enhancements

### Issue  
The backend code had several issues that prevented proper functioning of
API endpoints, including incorrect file naming, invalid routes, and
improper authentication handling. These issues resulted in failure to
connect to the database and authenticate users.


### Description of Changes

1. **Corrected Auth Router Endpoint:**  
   - The route for the `auth` router API endpoint was incorrect.  
   - Fixed the route to align with the intended functionality.  

2. **Updated Logout Request Method:**  
- Changed the HTTP method for the `logout` API from `GET` to `POST`.
   - This follows REST best practices.  

3. **Minor Fixes in `authController.js`:**  
   - Corrected HTTP status codes for consistent responses.  
- Added a **JWT token** to the response payload upon successful login.
   - Removed unnecessary console log statements for cleaner code.  
   - Improved response messages for better clarity.  

4. **Fixed JWT Auth Strategy:**  
- The `getUser` and `logout` API endpoints were failing because the JWT
strategy only checked for tokens in **cookies**.
- Updated the strategy to validate tokens from the `Authorization`
header (bearer token).

---

### **Files Changed**  

1. `app.js`  
- Updated the authRouter configuration by ensuring it is correctly
mounted at `/api/auth`. This ensures all authentication-related
endpoints are accessible under this base route.

2. `authRouter.js`  
   - Fixed incorrect endpoint routes.  
   - Updated logout method to `POST`.  

3. `authController.js`  
- Updated status codes, response payloads, and removed unnecessary logs.

4. `jwt.strategy.js`  
   - Modified to check for tokens in the `Authorization` header.  

---

### Screenshots of API endpoints testing

1. **API Testing: `api/auth/signin`**  
-
![Signin](https://github.com/user-attachments/assets/ffa092d3-a6e2-4aef-9440-724f3899cc77)

2. **API Testing: `api/auth/signup`**  
-
![Signup](https://github.com/user-attachments/assets/a4a8d0c1-2b59-4108-a31a-02e1d9e2d565)


3. **API Testing: `api/auth/user`**  
-
![User](https://github.com/user-attachments/assets/cfb7e646-8dc4-420f-83b3-3f753f6dbcb5)


4. **API Testing: `api/auth/logout`**  
-
![Logout](https://github.com/user-attachments/assets/71353b61-3dd1-4ff9-b0e0-9306ce93726b)


---


## Checklist
<!-- [X] - put a cross/X inside [] to check the box -->
- [X] I have gone through the [contributing
guide](https://github.com/Anjaliavv51/Retro)
- [X] I have updated my branch and synced it with project `main` branch
before making this PR
- [X] I have performed a self-review of my code
- [X] I have tested the changes thoroughly before submitting this pull
request.
- [X] I have provided relevant issue numbers, screenshots, and videos
after making the changes.
- [X] I have commented my code, particularly in hard-to-understand
areas.


@Anjaliavv51 please review this PR. Let me know if further adjustments
are needed.
Thank you for reviewing this PR! 🙌
  • Loading branch information
Anjaliavv51 authored Jan 14, 2025
2 parents 55ffccc + 6137f3e commit e7ef763
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 67 deletions.
38 changes: 30 additions & 8 deletions backend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,42 @@ const authRouter = require('./router/authRoute.js');
const databaseconnect = require('./config/databaseConfig.js');
const cookieParser = require('cookie-parser');
const cors = require('cors');
const csrf = require('csurf');
const rateLimit = require('express-rate-limit');

// connect to db
// Initialize CSRF Protection
const csrfProtect = csrf({ cookie: true });

// Define a rate limiter
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP, please try again later.',
});

// Connect to DB
databaseconnect();

app.use(express.json()); // Built-in middleware
app.use(cookieParser()); // Third-party middleware
// Middleware
app.use(express.json());
app.use(cookieParser());
app.use(cors({ origin: [process.env.CLIENT_URL], credentials: true }));

app.use(cors({ origin: [process.env.CLIENT_URL], credentials: true })); //Third-party middleware
// Expose CSRF token to client
app.get('/csrf-token', csrfProtect, (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});

// Auth router
app.use('/auth', authRouter);
// Auth routes
app.use('/api/auth', csrfProtect, limiter, authRouter);

app.use('/', (req, res) => {
res.status(200).json({ data: 'JWTauth server ;)' });
// Global error handler
app.use((err, req, res, next) => {
if (err.code === 'EBADCSRFTOKEN') {
res.status(403).json({ error: 'Invalid CSRF token' });
} else {
res.status(500).json({ error: 'Something went wrong' });
}
});

module.exports = app;
5 changes: 0 additions & 5 deletions backend/backendcode.ev

This file was deleted.

82 changes: 48 additions & 34 deletions backend/controller/authController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const userModel = require("../model/userSchema.js");
const bcrypt = require("bcrypt");
const userModel = require('../model/userSchema.js');
const bcrypt = require('bcrypt');

const emailValidator = require("email-validator");
const emailValidator = require('email-validator');

/******************************************************
* @SIGNUP
Expand All @@ -14,12 +14,12 @@ const emailValidator = require("email-validator");

const signUp = async (req, res, next) => {
const { name, email, password, confirmPassword } = req.body;
console.log(name , email,password,confirmPassword)
// console.log(name, email, password, confirmPassword);
/// every field is required
if (!name || !email || !password || !confirmPassword) {
return res.status(400).json({
success: false,
message: "Every field is required"
message: 'Every field is required',
});
}

Expand All @@ -28,7 +28,7 @@ console.log(name , email,password,confirmPassword)
if (!validEmail) {
return res.status(400).json({
success: false,
message: "Please provide a valid email address 📩"
message: 'Please provide a valid email address 📩',
});
}

Expand All @@ -37,7 +37,7 @@ console.log(name , email,password,confirmPassword)
if (password !== confirmPassword) {
return res.status(400).json({
success: false,
message: "password and confirm Password does not match ❌"
message: 'password and confirm Password does not match ❌',
});
}

Expand All @@ -48,19 +48,20 @@ console.log(name , email,password,confirmPassword)
const result = await userInfo.save();
return res.status(200).json({
success: true,
data: result
message: 'Registered successfully',
data: result,
});
} catch (error) {
/// send the message of the email is not unique.
if (error.code === 11000) {
return res.status(400).json({
success: false,
message: `Account already exist with the provided email ${email} 😒`
message: `Account already exist with the provided email ${email} 😒`,
});
}

return res.status(400).json({
message: error.message
message: error.message,
});
}
};
Expand All @@ -76,30 +77,30 @@ console.log(name , email,password,confirmPassword)

const signIn = async (req, res, next) => {
const { email, password } = req.body;
console.log(email,password)
// console.log(email,password)

// send response with error message if email or password is missing
if (!email || !password) {
return res.status(400).json({
success: false,
message: "email and password are required"
message: 'email and password are required',
});
}

try {
// check user exist or not
const user = await userModel
.findOne({
email
email,
})
.select("+password");
.select('+password');

// If user is null or the password is incorrect return response with error message
if (!user || !(await bcrypt.compare(password, user.password))) {
// bcrypt.compare returns boolean value
return res.status(400).json({
success: false,
message: "invalid credentials"
message: 'invalid credentials',
});
}

Expand All @@ -108,25 +109,26 @@ const signIn = async (req, res, next) => {
user.password = undefined;

const cookieOption = {
secure:true,
secure: true,
maxAge: 24 * 60 * 60 * 1000, //24hr
httpOnly: true // not able to modify the cookie in client side
httpOnly: true, // not able to modify the cookie in client side
};

res.cookie("token", token, cookieOption);
res.cookie('token', token, cookieOption);
res.status(200).json({
success: true,
data: user
message: 'Login successful',
data: user,
token,
});
} catch (error) {
return res.status(400).json({
success: false,
message: error.message
message: error.message,
});
}
};


/******************************************************
* @LOGOUT
* @route /api/auth/logout
Expand All @@ -139,19 +141,22 @@ const logout = async (req, res, next) => {
try {
const cookieOption = {
expires: new Date(Date.now()), // current expiry date
httpOnly: true // not able to modify the cookie in client side
httpOnly: true, // cookie cannot be modified in client-side JS
secure: process.env.NODE_ENV === 'production', // secure cookie if in production
sameSite: 'None', // allows cross-site cookie sharing if needed
};

// return response with cookie without token
res.cookie("token", null, cookieOption);
res.status(200).json({
// Remove the token from the cookie by setting it to null
res.cookie('token', null, cookieOption);

return res.status(200).json({
success: true,
message: "Logged Out"
message: 'Logged out successfully',
});
} catch (error) {
res.stats(400).json({
res.status(400).json({
success: false,
message: error.message
message: error.message,
});
}
};
Expand All @@ -165,26 +170,35 @@ const logout = async (req, res, next) => {
******************************************************/

const getUser = async (req, res, next) => {
const userId = req.user.id;
try {
// Assuming that `req.user.id` has been set in the jwtAuth middleware
const userId = req.user.id;

// Find the user by ID from the database (ensure you're using the correct model)
const user = await userModel.findById(userId);

if (!user) {
return res.status(404).json({
success: false,
message: 'User not found',
});
}

return res.status(200).json({
success: true,
data: user
data: user,
});
} catch (error) {
return res.status(400).json({
success: false,
message: error.message
message: error.message,
});
}
};

module.exports = {
signUp,
signIn,

getUser,

logout
logout,
};
27 changes: 17 additions & 10 deletions backend/middleware/jwtAuth.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
const JWT = require("jsonwebtoken");
const JWT = require('jsonwebtoken');

// router level middleware function
// Middleware to check for a valid JWT token
const jwtAuth = (req, res, next) => {

// get cookie token(jwt token generated using json.sign()) form the request
const token = ( req.cookies?.token) || null;
// Check if the token is in the cookies or the Authorization header
const token = req.cookies?.token || req.headers?.authorization?.split(' ')[1]; // Bearer <token>

// return response if there is no token(jwt token attached with cookie)
if (!token) {
return res.status(400).json({ success: false, message: "NOT authorized" });
return res.status(400).json({
success: false,
message: 'Not authorized, no token provided',
});
}

// verify the token
try {
// Verify the token using the secret key
const payload = JWT.verify(token, process.env.SECRET);

// Attach the payload data to the request object (i.e., user data)
req.user = { id: payload.id, email: payload.email };

next();
} catch (error) {
return res.status(400).json({ success: false, message: error.message });
return res.status(400).json({
success: false,
message: 'Token verification failed: ' + error.message,
});
}
next();
};

module.exports = jwtAuth;
2 changes: 2 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
"bcrypt": "^5.1.1",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"csurf": "^1.11.0",
"dotenv": "^16.4.5",
"email-validator": "^2.0.4",
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.9.3",
"nodemon": "^3.1.5"
Expand Down
18 changes: 8 additions & 10 deletions backend/router/authRoute.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
const express = require("express");
const express = require('express');
const authRouter = express.Router();
const jwtAuth = require("../middleware/jwtAuth.js");
const jwtAuth = require('../middleware/jwtAuth.js');

const {
signUp,
signIn,
forgotPassword,
resetPassword,
getUser,
logout
} = require("../controller/authController.js");
logout,
} = require('../controller/authController.js');

authRouter.post("/signup", signUp);
authRouter.post("/signin", signIn);


authRouter.get("/user", jwtAuth, getUser);
authRouter.get("/logout", jwtAuth, logout);
authRouter.post('/signup', signUp);
authRouter.post('/signin', signIn);
authRouter.post('/logout', jwtAuth, logout);
authRouter.get('/user', jwtAuth, getUser);

module.exports = authRouter;

0 comments on commit e7ef763

Please sign in to comment.