Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 34 additions & 60 deletions middleware/authenticateToken.js
Original file line number Diff line number Diff line change
@@ -1,94 +1,68 @@
const authService = require('../services/authService');

/**
* Enhanced authentication middleware
* Access Token Authentication Middleware
* - Verifies JWT access tokens only
* - Attaches decoded user payload to req.user
*/
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (!token) {
return res.status(401).json({
success: false,
error: 'Access token required',
code: 'TOKEN_MISSING'
});
}

try {
const decoded = authService.verifyAccessToken(token);
const authHeader = req.headers.authorization;

// optional check
if (decoded.type && decoded.type !== 'access') {
if (!authHeader) {
return res.status(401).json({
success: false,
error: 'Invalid token type',
code: 'INVALID_TOKEN_TYPE'
error: 'Authorization header missing',
code: 'TOKEN_MISSING'
});
}

// ✅ safer payload validation
if (!decoded.userId || !decoded.role) {
const parts = authHeader.split(' ');
if (parts.length !== 2 || parts[0] !== 'Bearer') {
return res.status(401).json({
success: false,
error: 'Invalid token payload',
code: 'INVALID_TOKEN'
error: 'Invalid authorization format',
code: 'INVALID_AUTH_HEADER'
});
}

req.user = decoded; // THIS FIXES PROFILE FETCH
next();
const token = parts[1];

} catch (error) {
if (error.name === 'TokenExpiredError') {
const decoded = authService.verifyAccessToken(token);

// Ensure only access tokens are accepted
if (!decoded || decoded.type !== 'access') {
return res.status(401).json({
success: false,
error: 'Access token expired',
code: 'TOKEN_EXPIRED'
error: 'Invalid token type',
code: 'INVALID_TOKEN_TYPE'
});
}

if (error.name === 'JsonWebTokenError') {
// Validate payload
if (!decoded.userId || !decoded.role) {
return res.status(401).json({
success: false,
error: 'Invalid access token',
error: 'Invalid token payload',
code: 'INVALID_TOKEN'
});
}

console.error('Token verification error:', error);
return res.status(500).json({
// Attach user to request
req.user = {
userId: decoded.userId,
email: decoded.email,
role: decoded.role
};

next();
} catch (error) {
return res.status(401).json({
success: false,
error: 'Internal server error',
code: 'INTERNAL_ERROR'
error: 'Invalid or expired access token',
code: 'TOKEN_INVALID'
});
}
};

/**
* Optional authentication middleware
* (attaches user if token exists, otherwise continues without blocking)
*/
const optionalAuth = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (!token) {
req.user = null;
return next();
}

try {
const decoded = authService.verifyAccessToken(token);
req.user = decoded;
} catch (error) {
req.user = null;
}

next();
};

module.exports = {
authenticateToken,
optionalAuth
};
module.exports = { authenticateToken };
107 changes: 62 additions & 45 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"license": "ISC",
"dependencies": {
"@sendgrid/mail": "^8.1.3",
"@supabase/supabase-js": "^2.40.0",
"@supabase/supabase-js": "^2.86.0",
"base64-arraybuffer": "^1.0.2",
"bcrypt": "^5.1.1",
"bcryptjs": "^2.4.3",
Expand All @@ -48,7 +48,7 @@
"yamljs": "^0.3.0"
},
"devDependencies": {
"axios": "^1.11.0",
"axios": "^1.13.2",
"chai": "^6.0.1",
"chai-http": "^5.1.2",
"concurrently": "^8.2.2",
Expand Down
2 changes: 1 addition & 1 deletion routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ router.get('/health', (req, res) => {
});
});

module.exports = router;
module.exports = router;
Loading
Loading