Files
gameno-api/components/auth/authService.js
T
kavehhn f04c797be6 Initial commit: teaching institution management API.
Express/MongoDB backend with JWT auth, RBAC, S3 uploads, notifications, and scheduled jobs.
2026-08-09 04:18:08 +02:00

111 lines
2.8 KiB
JavaScript

// /components/auth/authService.js
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const User = require('../users/userModel');
const config = require('../../config/config');
const AppError = require('../../utils/AppError');
const generateTokens = (user) => {
const payload = {
id: user._id,
username: user.username,
role: user.role?._id || user.role
};
const accessToken = jwt.sign(payload, config.JWT_ACCESS_SECRET, {
expiresIn: config.JWT_ACCESS_EXPIRES_IN
});
const refreshToken = jwt.sign({ id: user._id }, config.JWT_REFRESH_SECRET, {
expiresIn: config.JWT_REFRESH_EXPIRES_IN
});
return { accessToken, refreshToken };
};
const login = async (username, password) => {
const user = await User.findOne({ username }).populate('role');
if (!user || !user.isActive) {
throw new AppError('INVALID_CREDENTIALS');
}
const isMatch = await bcrypt.compare(password, user.passwordHash);
if (!isMatch) {
throw new AppError('INVALID_CREDENTIALS');
}
const { accessToken, refreshToken: refreshTokenString } = generateTokens(user);
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + 7);
user.refreshTokens.push({ token: refreshTokenString, expiresAt });
await user.save();
const userObject = user.toObject();
delete userObject.passwordHash;
delete userObject.refreshTokens;
return {
user: userObject,
accessToken,
refreshToken: refreshTokenString
};
};
const refreshToken = async (refreshTokenString) => {
let decoded;
try {
decoded = jwt.verify(refreshTokenString, config.JWT_REFRESH_SECRET);
} catch (err) {
throw new AppError('INVALID_REFRESH_TOKEN');
}
const user = await User.findById(decoded.id).populate('role');
if (!user || !user.isActive) {
throw new AppError('INVALID_REFRESH_TOKEN');
}
const tokenIndex = user.refreshTokens.findIndex(rt => rt.token === refreshTokenString);
if (tokenIndex === -1) {
throw new AppError('INVALID_REFRESH_TOKEN');
}
if (new Date() > new Date(user.refreshTokens[tokenIndex].expiresAt)) {
user.refreshTokens.splice(tokenIndex, 1);
await user.save();
throw new AppError('TOKEN_EXPIRED');
}
user.refreshTokens.splice(tokenIndex, 1);
const { accessToken, refreshToken: newRefreshToken } = generateTokens(user);
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + 7);
user.refreshTokens.push({ token: newRefreshToken, expiresAt });
await user.save();
return {
accessToken,
refreshToken: newRefreshToken
};
};
const logout = async (userId, refreshTokenString) => {
const user = await User.findById(userId);
if (user) {
user.refreshTokens = user.refreshTokens.filter(rt => rt.token !== refreshTokenString);
await user.save();
}
return true;
};
module.exports = {
login,
refreshToken,
logout
};