Skip to content

Commit da01408

Browse files
committed
Refactor backend authentication logic to use environment configuration; implement token generation and refresh functionality; enhance error handling and validation in login and registration routes.
1 parent 9e9a4af commit da01408

10 files changed

Lines changed: 1151 additions & 185 deletions

File tree

backend/SECURITY_SETUP.md

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# STRbook Security Setup Guide
2+
3+
## 🔒 Security Improvements Implemented
4+
5+
## Environment Configuration
6+
7+
Create a `.env` file in the backend directory with the following variables:
8+
9+
```env
10+
# Database Configuration
11+
DB_USER=postgres
12+
DB_PASSWORD=your_secure_database_password_here
13+
DB_HOST=localhost
14+
DB_PORT=5432
15+
DB_NAME=str_book
16+
17+
# JWT Configuration - CRITICAL: Use strong, unique secrets!
18+
# Generate using: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
19+
JWT_SECRET=your_super_secret_jwt_key_at_least_32_characters_long_replace_this_in_production
20+
JWT_REFRESH_SECRET=your_different_super_secret_refresh_jwt_key_replace_this_in_production
21+
22+
# JWT Token Expiration Times
23+
JWT_EXPIRE_TIME=15m
24+
JWT_REFRESH_EXPIRE_TIME=7d
25+
26+
# Server Configuration
27+
PORT=5000
28+
NODE_ENV=development
29+
30+
# CORS Configuration (comma-separated list)
31+
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001
32+
33+
# Rate Limiting Configuration
34+
RATE_LIMIT_WINDOW_MS=900000
35+
RATE_LIMIT_MAX_REQUESTS=100
36+
```
37+
38+
## 🛡️ Security Features Added
39+
40+
### 1. Environment Validation
41+
- Validates required environment variables on startup
42+
- Prevents startup with weak/default JWT secrets
43+
44+
### 2. JWT Security
45+
- Access tokens: 15 minutes
46+
- Refresh tokens: 7 days
47+
- Separate secrets for access and refresh tokens
48+
49+
### 3. Input Validation & Sanitization
50+
- Password strength requirements
51+
- Email validation and normalization
52+
- XSS protection
53+
54+
### 4. Rate Limiting
55+
- 100 requests per 15 minutes per IP
56+
- Configurable limits
57+
58+
### 5. Database Security
59+
- Connection pooling
60+
- SQL injection protection
61+
- Transaction support
62+
63+
### 6. Password Security
64+
- Bcrypt with 12 salt rounds
65+
- Constant-time password comparison
66+
67+
## 🚨 Production Security Checklist
68+
69+
Before deploying to production:
70+
71+
### Required Actions
72+
- [ ] Replace all default passwords and secrets
73+
- [ ] Generate strong JWT secrets (64+ characters)
74+
- [ ] Set `NODE_ENV=production`
75+
- [ ] Limit `ALLOWED_ORIGINS` to your domain only
76+
- [ ] Adjust rate limits for production traffic
77+
- [ ] Enable SSL/HTTPS
78+
- [ ] Use production database with restricted access
79+
- [ ] Set up proper logging and monitoring
80+
81+
### Generate Secure JWT Secrets
82+
```bash
83+
# Generate JWT secret
84+
node -e "console.log('JWT_SECRET=' + require('crypto').randomBytes(64).toString('hex'))"
85+
86+
# Generate refresh secret
87+
node -e "console.log('JWT_REFRESH_SECRET=' + require('crypto').randomBytes(64).toString('hex'))"
88+
```
89+
90+
### Recommended Production Settings
91+
```env
92+
NODE_ENV=production
93+
JWT_EXPIRE_TIME=15m
94+
JWT_REFRESH_EXPIRE_TIME=7d
95+
RATE_LIMIT_WINDOW_MS=900000
96+
RATE_LIMIT_MAX_REQUESTS=500
97+
```
98+
99+
## 🔄 New API Endpoints
100+
101+
### Authentication Endpoints
102+
103+
#### Register
104+
```http
105+
POST /api/auth/register
106+
Content-Type: application/json
107+
108+
{
109+
"email": "student@example.com",
110+
"password": "SecurePass123!",
111+
"confirmPassword": "SecurePass123!"
112+
}
113+
```
114+
115+
#### Login
116+
```http
117+
POST /api/auth/login
118+
Content-Type: application/json
119+
120+
{
121+
"email": "student@example.com",
122+
"password": "SecurePass123!"
123+
}
124+
```
125+
126+
#### Refresh Token
127+
```http
128+
POST /api/auth/refresh
129+
Content-Type: application/json
130+
131+
{
132+
"refreshToken": "your_refresh_token_here"
133+
}
134+
```
135+
136+
#### Logout
137+
```http
138+
POST /api/auth/logout
139+
Authorization: Bearer your_access_token_here
140+
```
141+
142+
### Response Format
143+
All authentication endpoints now return:
144+
```json
145+
{
146+
"message": "Login successful",
147+
"accessToken": "short_lived_access_token",
148+
"refreshToken": "long_lived_refresh_token",
149+
"user": {
150+
"id": 123,
151+
"email": "user@example.com",
152+
"role": "student",
153+
"is_first_login": true
154+
}
155+
}
156+
```
157+
158+
### Error Response Format
159+
```json
160+
{
161+
"message": "Validation failed",
162+
"code": "VALIDATION_ERROR",
163+
"errors": [
164+
{
165+
"field": "password",
166+
"message": "Password must contain at least one uppercase letter",
167+
"value": "weakpass"
168+
}
169+
]
170+
}
171+
```
172+
173+
## 🔧 Development Setup
174+
175+
1. **Install new dependencies**:
176+
```bash
177+
cd backend
178+
npm install express-rate-limit express-validator dotenv
179+
```
180+
181+
2. **Create environment file**:
182+
```bash
183+
cp .env.example .env
184+
# Edit .env with your configuration
185+
```
186+
187+
3. **Run with validation**:
188+
```bash
189+
npm start
190+
```
191+
192+
The server will validate your configuration on startup and provide clear error messages if anything is missing or insecure.
193+
194+
## 🔍 Security Monitoring
195+
196+
Monitor these security events:
197+
- Failed login attempts
198+
- Token refresh failures
199+
- Rate limit violations
200+
- Validation failures
201+
- Database connection errors
202+
203+
## 📞 Support
204+
205+
If you encounter any security-related issues:
206+
1. Check the console logs for specific error messages
207+
2. Verify your environment configuration
208+
3. Ensure all required dependencies are installed
209+
4. Test with the provided examples
210+
211+
## 🔗 References
212+
213+
- [OWASP Security Guidelines](https://owasp.org/)
214+
- [JWT Best Practices](https://tools.ietf.org/html/rfc7519)
215+
- [Node.js Security Checklist](https://blog.risingstack.com/node-js-security-checklist/)

backend/config/env.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const path = require('path');
2+
3+
require('dotenv').config({ path: path.join(__dirname, '../.env') });
4+
5+
function validateEnv() {
6+
const required = {
7+
DB_USER: process.env.DB_USER,
8+
DB_PASSWORD: process.env.DB_PASSWORD,
9+
DB_HOST: process.env.DB_HOST || 'localhost',
10+
DB_PORT: process.env.DB_PORT || '5432',
11+
DB_NAME: process.env.DB_NAME,
12+
JWT_SECRET: process.env.JWT_SECRET,
13+
PORT: process.env.PORT || '5000'
14+
};
15+
16+
const missing = [];
17+
const weak = [];
18+
19+
Object.entries(required).forEach(([key, value]) => {
20+
if (!value || value.trim() === '') {
21+
missing.push(key);
22+
}
23+
});
24+
25+
if (required.JWT_SECRET && required.JWT_SECRET.length < 32) {
26+
weak.push('JWT_SECRET must be at least 32 characters long');
27+
}
28+
29+
if (required.JWT_SECRET === 'your-secret-key' || required.JWT_SECRET === 'your-secret-key-here') {
30+
weak.push('JWT_SECRET is using default value - change it immediately');
31+
}
32+
33+
if (missing.length > 0) {
34+
console.error('❌ Missing required environment variables:');
35+
missing.forEach(key => console.error(` - ${key}`));
36+
process.exit(1);
37+
}
38+
39+
if (weak.length > 0) {
40+
console.error('⚠️ Weak security configuration:');
41+
weak.forEach(msg => console.error(` - ${msg}`));
42+
if (process.env.NODE_ENV === 'production') {
43+
console.error('❌ Cannot start in production with weak security settings');
44+
process.exit(1);
45+
}
46+
}
47+
48+
console.log('✅ Environment configuration validated');
49+
return required;
50+
}
51+
52+
const config = {
53+
database: {
54+
user: process.env.DB_USER,
55+
password: process.env.DB_PASSWORD,
56+
host: process.env.DB_HOST || 'localhost',
57+
port: parseInt(process.env.DB_PORT || '5432'),
58+
database: process.env.DB_NAME
59+
},
60+
61+
jwt: {
62+
secret: process.env.JWT_SECRET,
63+
refreshSecret: process.env.JWT_REFRESH_SECRET || process.env.JWT_SECRET + '_refresh',
64+
expiresIn: process.env.JWT_EXPIRE_TIME || '15m',
65+
refreshExpiresIn: process.env.JWT_REFRESH_EXPIRE_TIME || '7d'
66+
},
67+
68+
server: {
69+
port: parseInt(process.env.PORT || '5000'),
70+
nodeEnv: process.env.NODE_ENV || 'development'
71+
},
72+
73+
cors: {
74+
allowedOrigins: process.env.ALLOWED_ORIGINS ?
75+
process.env.ALLOWED_ORIGINS.split(',') :
76+
['http://localhost:3000', 'http://localhost:3001']
77+
},
78+
79+
rateLimit: {
80+
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'),
81+
maxRequests: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100')
82+
}
83+
};
84+
85+
validateEnv();
86+
87+
module.exports = config;

0 commit comments

Comments
 (0)