Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
37 lines
763 B
JavaScript
37 lines
763 B
JavaScript
const bcrypt = require('bcryptjs');
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
// Hash password with bcrypt
|
|
async function hashPassword(password) {
|
|
const salt = await bcrypt.genSalt(10);
|
|
return bcrypt.hash(password, salt);
|
|
}
|
|
|
|
// Compare password with hash
|
|
async function comparePassword(password, hash) {
|
|
return bcrypt.compare(password, hash);
|
|
}
|
|
|
|
// Generate JWT token
|
|
function generateToken(payload) {
|
|
return jwt.sign(payload, process.env.JWT_SECRET, {
|
|
expiresIn: process.env.JWT_EXPIRES_IN || '24h',
|
|
});
|
|
}
|
|
|
|
// Verify JWT token
|
|
function verifyToken(token) {
|
|
try {
|
|
return jwt.verify(token, process.env.JWT_SECRET);
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
hashPassword,
|
|
comparePassword,
|
|
generateToken,
|
|
verifyToken,
|
|
};
|