Fix session expiration handling

This commit is contained in:
2026-04-23 01:10:15 -05:00
parent da4b06094e
commit 820e335d9a
22 changed files with 308 additions and 51 deletions
+11 -9
View File
@@ -11,6 +11,7 @@ const { getCertificatePath } = require('../../utils/storagePath');
const { signAccess, signRefresh } = require('../../utils/jwt');
const fs = require('fs/promises');
const path = require('path');
const env = require('../../config/env');
const SALT_ROUNDS = 12;
const MAX_FAILED_LOGIN_ATTEMPTS = 3;
@@ -157,7 +158,7 @@ const login = async ({ email, password }, context = {}) => {
if (!user || !user.is_active) {
await auditService.logEvent({ type: 'LOGIN_FAILED', email, ip: context.ip, userAgent: context.userAgent });
const err = new Error('Invalid credentials.');
const err = new Error('Credenciales inválidas.');
err.statusCode = 401;
throw err;
}
@@ -210,7 +211,7 @@ const login = async ({ email, password }, context = {}) => {
throw err;
}
const err = new Error('Invalid credentials.');
const err = new Error('Credenciales inválidas.');
err.statusCode = 401;
throw err;
}
@@ -222,7 +223,7 @@ const login = async ({ email, password }, context = {}) => {
try {
({ verificationUrl } = await issueVerificationEmail(user));
} catch (error) {
const err = new Error('Your email is not verified and the verification email could not be resent. Please contact support.');
const err = new Error('Tu correo no está verificado y no se pudo reenviar el correo de confirmación. Contacta soporte.');
err.statusCode = 503;
err.code = 'MAIL_SEND_FAILED';
throw err;
@@ -235,7 +236,7 @@ const login = async ({ email, password }, context = {}) => {
userAgent: context.userAgent,
metadata: { source: 'login' },
});
const err = new Error('Your email is not verified yet. A new verification link has been sent to your email.');
const err = new Error('Tu correo aún no está verificado. Te enviamos un nuevo enlace de confirmación.');
err.statusCode = 403;
err.code = 'EMAIL_NOT_VERIFIED';
err.data = { verificationUrl };
@@ -246,7 +247,7 @@ const login = async ({ email, password }, context = {}) => {
const accessToken = signAccess(payload);
const refreshToken = signRefresh(payload);
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
const expiresAt = new Date(Date.now() + env.jwt.refreshExpiresMs);
await authRepository.saveRefreshToken(user.id, refreshToken, expiresAt);
await auditService.logEvent({ type: 'LOGIN_SUCCESS', userId: user.id, email, ip: context.ip, userAgent: context.userAgent });
@@ -268,21 +269,22 @@ const login = async ({ email, password }, context = {}) => {
const refresh = async (token) => {
if (!token) {
const err = new Error('Invalid or expired refresh token.');
const err = new Error('La sesión expiró. Vuelve a iniciar sesión.');
err.statusCode = 401;
throw err;
}
const record = await authRepository.findRefreshToken(token);
if (!record) {
const err = new Error('Invalid or expired refresh token.');
await authRepository.deleteRefreshToken(token);
const err = new Error('La sesión expiró. Vuelve a iniciar sesión.');
err.statusCode = 401;
throw err;
}
if (!record.is_active) {
await authRepository.deleteUserRefreshTokens(record.user_id);
const err = new Error('Session invalidated.');
const err = new Error('La sesión fue invalidada. Vuelve a iniciar sesión.');
err.statusCode = 401;
throw err;
}
@@ -292,7 +294,7 @@ const refresh = async (token) => {
const payload = { sub: record.uid, email: record.email, role: record.role };
const accessToken = signAccess(payload);
const newRefreshToken = signRefresh(payload);
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
const expiresAt = new Date(Date.now() + env.jwt.refreshExpiresMs);
await authRepository.saveRefreshToken(record.uid, newRefreshToken, expiresAt);
return { accessToken, refreshToken: newRefreshToken };