myex-cli
Version:
Opinionated Express.js framework with CLI tools
309 lines (275 loc) • 8.69 kB
JavaScript
import jwt from 'jsonwebtoken';
import bcrypt from 'bcryptjs';
import { logger } from '../utils/logger.js';
import { authService } from '../services/auth.service.js';
export const authController = {
/**
* Register a new user
* @param {import('express').Request} req - Express request object
* @param {import('express').Response} res - Express response object
*/
register: async (req, res) => {
try {
const { email, password, name } = req.body;
// Validate input
if (!email || !password || !name) {
return res.status(400).json({
status: 'error',
message: 'Email, password, and name are required',
});
}
// Check if user already exists
const existingUser = await authService.findUserByEmail(email);
if (existingUser) {
return res.status(409).json({
status: 'error',
message: 'User with this email already exists',
});
}
// Create new user
const user = await authService.createUser({
email,
password, // Will be hashed in the service
name,
role: 'user', // Default role
});
// Generate tokens
const accessToken = authService.generateAccessToken(user);
const refreshToken = authService.generateRefreshToken(user);
// Save refresh token to database
await authService.saveRefreshToken(user._id, refreshToken);
// Return success with tokens
res.status(201).json({
status: 'success',
message: 'User registered successfully',
data: {
user: {
id: user._id,
email: user.email,
name: user.name,
role: user.role,
},
tokens: {
accessToken,
refreshToken,
},
},
});
} catch (error) {
logger.error(`Registration error: ${error.message}`);
res.status(500).json({
status: 'error',
message: 'Failed to register user',
});
}
},
/**
* Login a user
* @param {import('express').Request} req - Express request object
* @param {import('express').Response} res - Express response object
*/
login: async (req, res) => {
try {
const { email, password } = req.body;
// Validate input
if (!email || !password) {
return res.status(400).json({
status: 'error',
message: 'Email and password are required',
});
}
// Find user by email
const user = await authService.findUserByEmail(email);
if (!user) {
return res.status(401).json({
status: 'error',
message: 'Invalid email or password',
});
}
// Check password
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
logger.warn(`Failed login attempt for user: ${email}`);
return res.status(401).json({
status: 'error',
message: 'Invalid email or password',
});
}
// Generate tokens
const accessToken = authService.generateAccessToken(user);
const refreshToken = authService.generateRefreshToken(user);
// Save refresh token to database
await authService.saveRefreshToken(user._id, refreshToken);
// Return success with tokens
res.status(200).json({
status: 'success',
message: 'Login successful',
data: {
user: {
id: user._id,
email: user.email,
name: user.name,
role: user.role,
},
tokens: {
accessToken,
refreshToken,
},
},
});
} catch (error) {
logger.error(`Login error: ${error.message}`);
res.status(500).json({
status: 'error',
message: 'Failed to login',
});
}
},
/**
* Refresh access token using refresh token
* @param {import('express').Request} req - Express request object
* @param {import('express').Response} res - Express response object
*/
refreshToken: async (req, res) => {
try {
const { refreshToken } = req.body;
if (!refreshToken) {
return res.status(400).json({
status: 'error',
message: 'Refresh token is required',
});
}
// Check if refresh token is valid
const user = await authService.verifyRefreshToken(refreshToken);
if (!user) {
return res.status(403).json({
status: 'error',
message: 'Invalid refresh token',
});
}
// Generate new access token
const newAccessToken = authService.generateAccessToken(user);
// Return new access token
res.status(200).json({
status: 'success',
message: 'Token refreshed successfully',
data: {
accessToken: newAccessToken,
},
});
} catch (error) {
logger.error(`Token refresh error: ${error.message}`);
res.status(500).json({
status: 'error',
message: 'Failed to refresh token',
});
}
},
/**
* Logout a user
* @param {import('express').Request} req - Express request object
* @param {import('express').Response} res - Express response object
*/
logout: async (req, res) => {
try {
const { refreshToken } = req.body;
if (!refreshToken) {
return res.status(400).json({
status: 'error',
message: 'Refresh token is required',
});
}
// Remove refresh token from database
await authService.removeRefreshToken(refreshToken);
res.status(200).json({
status: 'success',
message: 'Logged out successfully',
});
} catch (error) {
logger.error(`Logout error: ${error.message}`);
res.status(500).json({
status: 'error',
message: 'Failed to logout',
});
}
},
/**
* Initiate password reset process
* @param {import('express').Request} req - Express request object
* @param {import('express').Response} res - Express response object
*/
forgotPassword: async (req, res) => {
try {
const { email } = req.body;
if (!email) {
return res.status(400).json({
status: 'error',
message: 'Email is required',
});
}
// Check if user exists
const user = await authService.findUserByEmail(email);
if (!user) {
return res.status(404).json({
status: 'error',
message: 'User not found',
});
}
// Generate reset token and save it
const resetToken = await authService.generatePasswordResetToken(user._id);
// In a real app, send email with reset link here
// For now, just return the token in the response
res.status(200).json({
status: 'success',
message: 'Password reset instructions sent to email',
data: {
resetToken, // Remove this in production
},
});
} catch (error) {
logger.error(`Forgot password error: ${error.message}`);
res.status(500).json({
status: 'error',
message: 'Failed to process forgot password request',
});
}
},
/**
* Reset password with reset token
* @param {import('express').Request} req - Express request object
* @param {import('express').Response} res - Express response object
*/
resetPassword: async (req, res) => {
try {
const { token, newPassword } = req.body;
if (!token || !newPassword) {
return res.status(400).json({
status: 'error',
message: 'Token and new password are required',
});
}
// Verify and use the reset token
const userId = await authService.verifyPasswordResetToken(token);
if (!userId) {
return res.status(403).json({
status: 'error',
message: 'Invalid or expired reset token',
});
}
// Update password
await authService.updatePassword(userId, newPassword);
// Invalidate token
await authService.invalidatePasswordResetToken(token);
res.status(200).json({
status: 'success',
message: 'Password reset successfully',
});
} catch (error) {
logger.error(`Reset password error: ${error.message}`);
res.status(500).json({
status: 'error',
message: 'Failed to reset password',
});
}
},
};