Add security fixes and deployment configuration
Security fixes: - Remove hardcoded MongoDB credentials from server.js (fail fast in production) - Add OAuth state parameter validation for CSRF protection - Add input validation for unitCode parameter to prevent NoSQL injection - Add isValidUnitCode helper function Deployment: - Update docker-compose.yml to use env_file and environment variables - Create .env.example with all required configuration variables
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
const express = require('express');
|
||||
const passport = require('passport');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const crypto = require('crypto');
|
||||
const authConfig = require('../config/auth');
|
||||
const { requireAuth, generateToken } = require('../middleware/auth');
|
||||
const { logActivity, ACTIONS } = require('../services/activityLogger');
|
||||
@ -9,25 +10,53 @@ const router = express.Router();
|
||||
|
||||
/**
|
||||
* GET /auth/google
|
||||
* Initiates Google OAuth flow
|
||||
* Initiates Google OAuth flow with state parameter for CSRF protection
|
||||
*/
|
||||
router.get('/google', passport.authenticate('google', {
|
||||
scope: authConfig.google.scope,
|
||||
session: false
|
||||
}));
|
||||
router.get('/google', (req, res, next) => {
|
||||
// Generate cryptographically secure state parameter
|
||||
const state = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
// Store state in a short-lived cookie for validation
|
||||
res.cookie('oauth_state', state, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
maxAge: 5 * 60 * 1000 // 5 minutes
|
||||
});
|
||||
|
||||
passport.authenticate('google', {
|
||||
scope: authConfig.google.scope,
|
||||
session: false,
|
||||
state: state
|
||||
})(req, res, next);
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /auth/google/callback
|
||||
* Handles OAuth callback from Google
|
||||
* Validates state parameter for CSRF protection
|
||||
* On success: generates JWT, sets cookie, redirects to frontend
|
||||
* On failure: redirects to login with error
|
||||
*/
|
||||
router.get('/google/callback',
|
||||
router.get('/google/callback', (req, res, next) => {
|
||||
// Validate state parameter to prevent CSRF
|
||||
const stateFromCookie = req.cookies.oauth_state;
|
||||
const stateFromQuery = req.query.state;
|
||||
|
||||
// Clear the state cookie immediately
|
||||
res.clearCookie('oauth_state');
|
||||
|
||||
if (!stateFromCookie || !stateFromQuery || stateFromCookie !== stateFromQuery) {
|
||||
console.warn('OAuth state mismatch - potential CSRF attack');
|
||||
return res.redirect(`${process.env.FRONTEND_URL}/login?error=invalid_state`);
|
||||
}
|
||||
|
||||
// State is valid, proceed with authentication
|
||||
passport.authenticate('google', {
|
||||
session: false,
|
||||
failureRedirect: `${process.env.FRONTEND_URL}/login?error=auth_failed`
|
||||
}),
|
||||
async (req, res) => {
|
||||
})(req, res, next);
|
||||
}, async (req, res) => {
|
||||
try {
|
||||
const user = req.user;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user