trading-platform/docs/02-definicion-modulos/OQI-001-fundamentos-auth/requerimientos/RF-AUTH-005-sessions.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
Changes include:
- Updated architecture documentation
- Enhanced module definitions (OQI-001 to OQI-008)
- ML integration documentation updates
- Trading strategies documentation
- Orchestration and inventory updates
- Docker configuration updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:33:35 -06:00

15 KiB

id title type status priority module epic version created_date updated_date
RF-AUTH-005 Gestion de Sesiones Requirement Done Alta auth OQI-001 1.0 2025-12-05 2026-01-04

RF-AUTH-005: Gestión de Sesiones

Version: 1.0.0 Fecha: 2025-12-05 Estado: Implementado Prioridad: P0 (Crítica) Épica: OQI-001


Descripción

El sistema debe gestionar sesiones de usuario de forma segura, permitiendo múltiples dispositivos simultáneos, visualización de sesiones activas, y capacidad de revocar acceso de forma individual o global.


Objetivo de Negocio

  • Permitir acceso desde múltiples dispositivos
  • Dar control al usuario sobre sus sesiones
  • Detectar y prevenir accesos no autorizados
  • Cumplir con regulaciones de seguridad

Requisitos Funcionales

RF-AUTH-005.1: Creación de Sesión

DEBE:

  1. Crear sesión al login exitoso
  2. Registrar información del dispositivo
  3. Registrar IP y ubicación aproximada
  4. Generar refresh token único
  5. Establecer tiempo de expiración (7 días)

RF-AUTH-005.2: Tokens JWT

DEBE:

  1. Access token con TTL corto (15 min)
  2. Refresh token con TTL largo (7 días)
  3. Refresh token rotativo (nuevo en cada refresh)
  4. Invalidar refresh token anterior al rotar
  5. Almacenar hash del refresh token en DB

RF-AUTH-005.3: Visualización de Sesiones

DEBE:

  1. Listar todas las sesiones activas
  2. Mostrar dispositivo, navegador, SO
  3. Mostrar IP y ubicación
  4. Mostrar fecha de último acceso
  5. Identificar sesión actual

RF-AUTH-005.4: Revocación de Sesiones

DEBE:

  1. Permitir cerrar sesión individual
  2. Permitir cerrar todas las sesiones
  3. Cerrar sesiones al cambiar contraseña
  4. Cerrar sesiones al desactivar cuenta

RF-AUTH-005.5: Detección de Anomalías

DEBE:

  1. Detectar login desde nueva ubicación
  2. Detectar login desde nuevo dispositivo
  3. Notificar al usuario de accesos sospechosos
  4. Registrar en audit log

Estructura de Sesión

Modelo de Datos

CREATE TABLE sessions (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    refresh_token_hash VARCHAR(255) NOT NULL,
    device_info JSONB NOT NULL,
    ip_address INET,
    location JSONB,
    user_agent TEXT,
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    last_activity TIMESTAMPTZ DEFAULT NOW(),
    expires_at TIMESTAMPTZ NOT NULL,
    revoked_at TIMESTAMPTZ,
    revoked_reason VARCHAR(100)
);

CREATE INDEX idx_sessions_user_id ON sessions(user_id);
CREATE INDEX idx_sessions_token_hash ON sessions(refresh_token_hash);
CREATE INDEX idx_sessions_expires ON sessions(expires_at) WHERE is_active = TRUE;

Device Info Structure

interface DeviceInfo {
  type: 'desktop' | 'mobile' | 'tablet';
  browser: string;
  browserVersion: string;
  os: string;
  osVersion: string;
  isMobile: boolean;
  deviceId?: string; // Fingerprint opcional
}

Location Structure

interface LocationInfo {
  country: string;
  countryCode: string;
  region: string;
  city: string;
  timezone: string;
  // Aproximado por IP, no GPS
}

Flujo de Tokens

Login y Generación

Usuario                    Frontend                   Backend                    DB
   │                          │                          │                        │
   │─── Login ───────────────▶│                          │                        │
   │                          │                          │                        │
   │                          │─── POST /auth/login ────▶│                        │
   │                          │    + User-Agent          │                        │
   │                          │    + IP                  │                        │
   │                          │                          │                        │
   │                          │                          │─── Validate creds ─────│
   │                          │                          │                        │
   │                          │                          │─── Parse device info ──│
   │                          │                          │─── Get location by IP ─│
   │                          │                          │                        │
   │                          │                          │─── Generate tokens ────│
   │                          │                          │    accessToken (15m)   │
   │                          │                          │    refreshToken (7d)   │
   │                          │                          │                        │
   │                          │                          │─── INSERT session ────▶│
   │                          │                          │    refresh_token_hash  │
   │                          │                          │    device_info         │
   │                          │                          │    ip, location        │
   │                          │                          │                        │
   │                          │◀── 200 OK ───────────────│                        │
   │                          │    { accessToken,        │                        │
   │                          │      refreshToken,       │                        │
   │                          │      expiresIn }         │                        │
   │                          │                          │                        │
   │◀── Store tokens ─────────│                          │                        │

Refresh Token Rotation

Frontend                   Backend                    DB
   │                          │                        │
   │─── POST /auth/refresh ──▶│                        │
   │    { refreshToken }      │                        │
   │                          │                        │
   │                          │─── Hash token ─────────│
   │                          │                        │
   │                          │─── Find session ──────▶│
   │                          │◀── session data ───────│
   │                          │                        │
   │                          │─── Validate:           │
   │                          │    - Token matches     │
   │                          │    - Not expired       │
   │                          │    - Session active    │
   │                          │                        │
   │                          │─── Generate NEW tokens │
   │                          │    newAccessToken      │
   │                          │    newRefreshToken     │
   │                          │                        │
   │                          │─── UPDATE session ────▶│
   │                          │    new token_hash      │
   │                          │    last_activity       │
   │                          │                        │
   │◀── 200 OK ───────────────│                        │
   │    { accessToken,        │                        │
   │      refreshToken }      │                        │

Gestión de Sesiones UI

Lista de Sesiones

┌─────────────────────────────────────────────────────────────────────────┐
│                        Sesiones Activas                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  🖥️  Windows · Chrome 120                              [Sesión actual]  │
│     Ciudad de México, México                                            │
│     Último acceso: Ahora                                                │
│     IP: 189.xxx.xxx.xxx                                                 │
│                                                                         │
│  ─────────────────────────────────────────────────────────────────────  │
│                                                                         │
│  📱  iPhone · Safari 17                                    [Revocar]   │
│     Guadalajara, México                                                 │
│     Último acceso: Hace 2 horas                                         │
│     IP: 187.xxx.xxx.xxx                                                 │
│                                                                         │
│  ─────────────────────────────────────────────────────────────────────  │
│                                                                         │
│  💻  MacOS · Firefox 121                                   [Revocar]   │
│     Monterrey, México                                                   │
│     Último acceso: Hace 3 días                                          │
│     IP: 201.xxx.xxx.xxx                                                 │
│                                                                         │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ⚠️  ¿No reconoces alguna sesión?                                       │
│     [Cerrar todas las demás sesiones]                                   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

API Endpoints

Listar Sesiones

GET /auth/sessions
Authorization: Bearer {accessToken}

Response 200:
{
  "sessions": [
    {
      "id": "uuid",
      "device": {
        "type": "desktop",
        "browser": "Chrome",
        "os": "Windows"
      },
      "location": {
        "city": "Ciudad de México",
        "country": "México"
      },
      "ipAddress": "189.xxx.xxx.xxx",
      "lastActivity": "2025-12-05T10:00:00Z",
      "createdAt": "2025-12-01T08:00:00Z",
      "isCurrent": true
    }
  ]
}

Revocar Sesión

DELETE /auth/sessions/{sessionId}
Authorization: Bearer {accessToken}

Response 200:
{
  "message": "Sesión cerrada exitosamente"
}

Revocar Todas las Sesiones

DELETE /auth/sessions
Authorization: Bearer {accessToken}

Response 200:
{
  "message": "Todas las demás sesiones han sido cerradas",
  "revokedCount": 3
}

Detección de Anomalías

Triggers de Alerta

Evento Acción
Nuevo dispositivo Email de notificación
Nueva ubicación (país) Email + notificación in-app
Login desde IP en blacklist Bloquear + notificar
Múltiples IPs en poco tiempo Notificar + audit log
Login en horario inusual Audit log

Email de Nuevo Dispositivo

Asunto: Nuevo inicio de sesión en tu cuenta OrbiQuant

Hola {{firstName}},

Detectamos un nuevo inicio de sesión en tu cuenta:

Dispositivo: {{device}}
Ubicación: {{location}}
Fecha: {{date}}
IP: {{ip}}

Si fuiste tú, puedes ignorar este mensaje.

Si NO fuiste tú:
1. Cambia tu contraseña inmediatamente
2. Activa 2FA si no lo tienes
3. Revisa tus sesiones activas

[Asegurar mi cuenta]

Saludos,
Equipo OrbiQuant

Limpieza de Sesiones

Job Programado

// Ejecutar cada hora
async function cleanupExpiredSessions() {
  await db.query(`
    UPDATE sessions
    SET is_active = FALSE,
        revoked_reason = 'expired'
    WHERE expires_at < NOW()
      AND is_active = TRUE
  `);
}

Retención de Datos

Tipo de Sesión Retención
Activa Hasta expiración o revocación
Revocada 30 días (audit)
Expirada 30 días (audit)

Configuración

const sessionConfig = {
  accessToken: {
    expiresIn: '15m',
    algorithm: 'RS256',
  },
  refreshToken: {
    expiresIn: '7d',
    algorithm: 'RS256',
  },
  session: {
    maxPerUser: 10, // Máximo sesiones simultáneas
    inactivityTimeout: '30d', // Auto-revoke si inactiva
  },
};

Manejo de Errores

Error Código Mensaje Usuario
Token expirado 401 Sesión expirada, inicia sesión
Token inválido 401 Token inválido
Sesión revocada 401 Sesión cerrada, inicia sesión
Sesión no encontrada 404 Sesión no encontrada
No autorizado 403 No puedes cerrar esta sesión
Límite de sesiones 400 Máximo de sesiones alcanzado

Seguridad

Almacenamiento de Tokens

  1. Access token: Solo en memoria (no localStorage)
  2. Refresh token: httpOnly cookie o secure storage
  3. Hash del refresh token en DB (no el token en sí)

Protección de Refresh

  1. Rotación en cada uso
  2. Detección de reuso (posible robo)
  3. Binding a device fingerprint (opcional)

Reuse Detection

Si un refresh token ya usado se presenta:

  1. Invalidar TODAS las sesiones del usuario
  2. Notificar al usuario
  3. Registrar en security log
  4. Posible cuenta comprometida

Criterios de Aceptación

  • Sesión se crea al login exitoso
  • Device info se detecta correctamente
  • Ubicación por IP funciona
  • Access token expira en 15 minutos
  • Refresh token renueva correctamente
  • Usuario puede ver sesiones activas
  • Usuario puede revocar sesión individual
  • Usuario puede revocar todas las sesiones
  • Notificación de nuevo dispositivo funciona
  • Sesiones se limpian al expirar

Especificación Técnica Relacionada

Historias de Usuario Relacionadas