backend: Refactor authentication controller to improve login flow and add user profile retrieval
This commit is contained in:
parent
d1af9637a6
commit
fbbef9eedf
@ -6,81 +6,56 @@ import { LoggerService } from '../services/logger.service.js';
|
||||
import {
|
||||
ACCESS_TOKEN_COOKIE_NAME,
|
||||
MEET_ACCESS_TOKEN_EXPIRATION,
|
||||
MEET_ADMIN_USER,
|
||||
MEET_API_BASE_PATH_V1,
|
||||
MEET_REFRESH_TOKEN_EXPIRATION,
|
||||
REFRESH_TOKEN_COOKIE_NAME
|
||||
} from '../environment.js';
|
||||
import { ClaimGrants } from 'livekit-server-sdk';
|
||||
import { getCookieOptions } from '../utils/cookie-utils.js';
|
||||
import { UserService } from '../services/user.service.js';
|
||||
|
||||
export const login = (req: Request, res: Response) => {
|
||||
export const login = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
logger.verbose('Login request received');
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
logger.warn('Missing username or password');
|
||||
return res.status(400).json({ message: 'Missing username or password' });
|
||||
}
|
||||
const { username, password } = req.body as { username: string; password: string };
|
||||
|
||||
const authService = container.get(AuthService);
|
||||
const authenticated = authService.authenticateUser(username, password);
|
||||
const user = authService.authenticate(username, password);
|
||||
|
||||
if (!authenticated) {
|
||||
if (!user) {
|
||||
logger.warn('Login failed');
|
||||
return res.status(401).json({ message: 'Login failed' });
|
||||
}
|
||||
|
||||
return res.status(200).json({ message: 'Login succeeded' });
|
||||
};
|
||||
|
||||
export const logout = (req: Request, res: Response) => {
|
||||
return res.status(200).json({ message: 'Logout successful' });
|
||||
};
|
||||
|
||||
export const adminLogin = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
logger.verbose('Admin login request received');
|
||||
const { username, password } = req.body;
|
||||
|
||||
const authService = container.get(AuthService);
|
||||
const authenticated = authService.authenticateAdmin(username, password);
|
||||
|
||||
if (!authenticated) {
|
||||
logger.warn(`Admin login failed for username: ${username}`);
|
||||
return res.status(404).json({ message: 'Admin login failed. Invalid username or password' });
|
||||
return res.status(404).json({ message: 'Login failed. Invalid username or password' });
|
||||
}
|
||||
|
||||
try {
|
||||
const tokenService = container.get(TokenService);
|
||||
const accessToken = await tokenService.generateAccessToken(username);
|
||||
const refreshToken = await tokenService.generateRefreshToken(username);
|
||||
const accessToken = await tokenService.generateAccessToken(user);
|
||||
const refreshToken = await tokenService.generateRefreshToken(user);
|
||||
res.cookie(ACCESS_TOKEN_COOKIE_NAME, accessToken, getCookieOptions('/', MEET_ACCESS_TOKEN_EXPIRATION));
|
||||
res.cookie(
|
||||
REFRESH_TOKEN_COOKIE_NAME,
|
||||
refreshToken,
|
||||
getCookieOptions(`${MEET_API_BASE_PATH_V1}/auth/admin`, MEET_REFRESH_TOKEN_EXPIRATION)
|
||||
getCookieOptions(`${MEET_API_BASE_PATH_V1}/auth`, MEET_REFRESH_TOKEN_EXPIRATION)
|
||||
);
|
||||
logger.info(`Admin login succeeded for username: ${username}`);
|
||||
return res.status(200).json({ message: 'Admin login succeeded' });
|
||||
logger.info(`Login succeeded for user ${username}`);
|
||||
return res.status(200).json({ message: 'Login succeeded' });
|
||||
} catch (error) {
|
||||
logger.error('Error generating admin token' + error);
|
||||
logger.error('Error generating token' + error);
|
||||
return res.status(500).json({ message: 'Internal server error' });
|
||||
}
|
||||
};
|
||||
|
||||
export const adminLogout = (req: Request, res: Response) => {
|
||||
export const logout = (_req: Request, res: Response) => {
|
||||
res.clearCookie(ACCESS_TOKEN_COOKIE_NAME);
|
||||
res.clearCookie(REFRESH_TOKEN_COOKIE_NAME, {
|
||||
path: `${MEET_API_BASE_PATH_V1}/auth/admin`
|
||||
path: `${MEET_API_BASE_PATH_V1}/auth`
|
||||
});
|
||||
return res.status(200).json({ message: 'Logout successful' });
|
||||
};
|
||||
|
||||
export const adminRefresh = async (req: Request, res: Response) => {
|
||||
export const refreshToken = async (req: Request, res: Response) => {
|
||||
const logger = container.get(LoggerService);
|
||||
logger.verbose('Admin refresh request received');
|
||||
logger.verbose('Refresh token request received');
|
||||
const refreshToken = req.cookies[REFRESH_TOKEN_COOKIE_NAME];
|
||||
|
||||
if (!refreshToken) {
|
||||
@ -98,18 +73,32 @@ export const adminRefresh = async (req: Request, res: Response) => {
|
||||
return res.status(400).json({ message: 'Invalid refresh token' });
|
||||
}
|
||||
|
||||
if (payload.sub !== MEET_ADMIN_USER) {
|
||||
const username = payload.sub;
|
||||
const userService = container.get(UserService);
|
||||
const user = username ? userService.getUser(username) : null;
|
||||
|
||||
if (!user) {
|
||||
logger.warn('Invalid refresh token subject');
|
||||
return res.status(403).json({ message: 'Invalid refresh token subject' });
|
||||
}
|
||||
|
||||
try {
|
||||
const accessToken = await tokenService.generateAccessToken(MEET_ADMIN_USER);
|
||||
const accessToken = await tokenService.generateAccessToken(user);
|
||||
res.cookie(ACCESS_TOKEN_COOKIE_NAME, accessToken, getCookieOptions('/', MEET_ACCESS_TOKEN_EXPIRATION));
|
||||
logger.info(`Admin refresh succeeded for username: ${MEET_ADMIN_USER}`);
|
||||
return res.status(200).json({ message: 'Admin refresh succeeded' });
|
||||
logger.info(`Token refreshed for user ${username}`);
|
||||
return res.status(200).json({ message: 'Token refreshed' });
|
||||
} catch (error) {
|
||||
logger.error('Error refreshing admin token' + error);
|
||||
logger.error('Error refreshing token' + error);
|
||||
return res.status(500).json({ message: 'Internal server error' });
|
||||
}
|
||||
};
|
||||
|
||||
export const getProfile = (req: Request, res: Response) => {
|
||||
const user = req.session?.user;
|
||||
|
||||
if (!user) {
|
||||
return res.status(401).json({ message: 'Unauthorized' });
|
||||
}
|
||||
|
||||
return res.status(200).json(user);
|
||||
};
|
||||
|
||||
@ -1,27 +1,29 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { Router } from 'express';
|
||||
import bodyParser from 'body-parser';
|
||||
import * as authCtrl from '../controllers/auth.controller.js';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { withAdminValidToken } from '../middlewares/auth.middleware.js';
|
||||
import { tokenAndRoleValidator, withAuth } from '../middlewares/auth.middleware.js';
|
||||
import { Role } from '@typings-ce';
|
||||
import { validateLoginRequest } from '../middlewares/request-validators/auth-validator.middleware.js';
|
||||
|
||||
export const authRouter = Router();
|
||||
|
||||
// Limit login attempts for avoiding brute force attacks
|
||||
const loginLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 min
|
||||
max: 5,
|
||||
message: 'Too many login attempts, please try again later.'
|
||||
limit: 5,
|
||||
message: 'Too many login attempts, please try again later'
|
||||
});
|
||||
|
||||
authRouter.use(bodyParser.urlencoded({ extended: true }));
|
||||
authRouter.use(bodyParser.json());
|
||||
|
||||
// Auth Routes
|
||||
authRouter.post('/login', authCtrl.login);
|
||||
authRouter.post('/login', validateLoginRequest, loginLimiter, authCtrl.login);
|
||||
authRouter.post('/logout', authCtrl.logout);
|
||||
authRouter.post('/admin/login', loginLimiter, authCtrl.adminLogin);
|
||||
authRouter.post('/admin/logout', authCtrl.adminLogout);
|
||||
authRouter.post('/admin/refresh', authCtrl.adminRefresh);
|
||||
authRouter.get('/admin/verify', withAdminValidToken, (_req: Request, res: Response) =>
|
||||
res.status(200).json({ message: 'Valid token' })
|
||||
authRouter.post('/refresh', authCtrl.refreshToken);
|
||||
authRouter.get(
|
||||
'/profile',
|
||||
withAuth(tokenAndRoleValidator(Role.ADMIN), tokenAndRoleValidator(Role.USER)),
|
||||
authCtrl.getProfile
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user