trading-platform/docs/02-definicion-modulos/OQI-001-fundamentos-auth/especificaciones/ET-AUTH-004-api.md

813 lines
13 KiB
Markdown

# ET-AUTH-004: Especificación Técnica - API Endpoints
**Version:** 1.0.0
**Fecha:** 2025-12-05
**Estado:** ✅ Implementado
**Épica:** [OQI-001](../_MAP.md)
---
## Resumen
Esta especificación detalla todos los endpoints de la API de autenticación de OrbiQuant IA.
---
## Base URL
```
Production: https://api.orbiquant.com/api/v1
Development: http://localhost:3000/api/v1
```
---
## Endpoints Overview
| Método | Endpoint | Descripción | Auth |
|--------|----------|-------------|------|
| POST | `/auth/register` | Registro con email | ❌ |
| POST | `/auth/login` | Login con email/password | ❌ |
| POST | `/auth/logout` | Cerrar sesión | ✅ |
| POST | `/auth/refresh` | Renovar tokens | ❌ |
| GET | `/auth/me` | Usuario actual | ✅ |
| GET | `/auth/oauth/:provider/url` | URL de OAuth | ❌ |
| POST | `/auth/oauth/:provider` | Callback OAuth | ❌ |
| DELETE | `/auth/oauth/:provider` | Desvincular OAuth | ✅ |
| POST | `/auth/phone/send` | Enviar OTP | ❌ |
| POST | `/auth/phone/verify` | Verificar OTP | ❌ |
| POST | `/auth/2fa/setup` | Configurar 2FA | ✅ |
| POST | `/auth/2fa/enable` | Activar 2FA | ✅ |
| POST | `/auth/2fa/verify` | Verificar 2FA | ❌ |
| POST | `/auth/2fa/disable` | Desactivar 2FA | ✅ |
| POST | `/auth/forgot-password` | Solicitar reset | ❌ |
| POST | `/auth/reset-password` | Cambiar password | ❌ |
| POST | `/auth/verify-email` | Verificar email | ❌ |
| GET | `/auth/sessions` | Listar sesiones | ✅ |
| DELETE | `/auth/sessions/:id` | Revocar sesión | ✅ |
| DELETE | `/auth/sessions` | Revocar todas | ✅ |
---
## Detalle de Endpoints
### POST /auth/register
Registro de nuevo usuario con email y contraseña.
**Request:**
```http
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "usuario@example.com",
"password": "SecurePass123!",
"firstName": "Juan",
"lastName": "Pérez",
"acceptTerms": true
}
```
**Response 201:**
```json
{
"success": true,
"message": "Registro exitoso. Revisa tu email para verificar tu cuenta.",
"data": {
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "usuario@example.com",
"firstName": "Juan",
"lastName": "Pérez",
"role": "investor",
"status": "pending_verification",
"emailVerified": false
}
}
}
```
**Errors:**
| Code | Error | Descripción |
|------|-------|-------------|
| 400 | VALIDATION_ERROR | Datos inválidos |
| 409 | EMAIL_EXISTS | Email ya registrado |
| 429 | RATE_LIMIT | Demasiadas solicitudes |
---
### POST /auth/login
Inicio de sesión con email y contraseña.
**Request:**
```http
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "usuario@example.com",
"password": "SecurePass123!"
}
```
**Response 200 (sin 2FA):**
```json
{
"success": true,
"data": {
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "usuario@example.com",
"firstName": "Juan",
"lastName": "Pérez",
"role": "investor",
"status": "active"
},
"tokens": {
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"refreshToken": "eyJhbGciOiJSUzI1NiIs...",
"expiresIn": 900,
"tokenType": "Bearer"
}
}
}
```
**Response 200 (con 2FA):**
```json
{
"success": true,
"data": {
"requires2FA": true,
"tempToken": "temp_token_for_2fa_verification",
"methods": ["totp", "backup_code"]
}
}
```
**Errors:**
| Code | Error | Descripción |
|------|-------|-------------|
| 401 | INVALID_CREDENTIALS | Email o contraseña incorrectos |
| 403 | EMAIL_NOT_VERIFIED | Email no verificado |
| 403 | ACCOUNT_LOCKED | Cuenta bloqueada temporalmente |
| 403 | ACCOUNT_SUSPENDED | Cuenta suspendida |
---
### POST /auth/logout
Cerrar sesión actual.
**Request:**
```http
POST /api/v1/auth/logout
Authorization: Bearer {accessToken}
```
**Response 200:**
```json
{
"success": true,
"message": "Sesión cerrada exitosamente"
}
```
---
### POST /auth/refresh
Renovar access token usando refresh token.
**Request:**
```http
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refreshToken": "eyJhbGciOiJSUzI1NiIs..."
}
```
**Response 200:**
```json
{
"success": true,
"data": {
"tokens": {
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"refreshToken": "eyJhbGciOiJSUzI1NiIs...",
"expiresIn": 900,
"tokenType": "Bearer"
}
}
}
```
**Errors:**
| Code | Error | Descripción |
|------|-------|-------------|
| 401 | INVALID_TOKEN | Token inválido o expirado |
| 401 | TOKEN_REVOKED | Token revocado |
---
### GET /auth/me
Obtener información del usuario actual.
**Request:**
```http
GET /api/v1/auth/me
Authorization: Bearer {accessToken}
```
**Response 200:**
```json
{
"success": true,
"data": {
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "usuario@example.com",
"phone": "+525512345678",
"firstName": "Juan",
"lastName": "Pérez",
"role": "investor",
"status": "active",
"emailVerified": true,
"phoneVerified": true,
"twoFactorEnabled": false,
"createdAt": "2025-01-15T10:00:00Z",
"profile": {
"displayName": "JuanPerez",
"avatarUrl": "https://...",
"preferredLanguage": "es",
"timezone": "America/Mexico_City"
},
"oauthProviders": ["google", "github"]
}
}
}
```
---
### GET /auth/oauth/:provider/url
Obtener URL de autorización OAuth.
**Request:**
```http
GET /api/v1/auth/oauth/google/url?redirectTo=/dashboard
```
**Response 200:**
```json
{
"success": true,
"data": {
"authUrl": "https://accounts.google.com/o/oauth2/v2/auth?...",
"state": "random_state_token"
}
}
```
---
### POST /auth/oauth/:provider
Procesar callback de OAuth.
**Request:**
```http
POST /api/v1/auth/oauth/google
Content-Type: application/json
{
"code": "authorization_code_from_provider",
"state": "state_token_from_url"
}
```
**Response 200:**
```json
{
"success": true,
"data": {
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "usuario@gmail.com",
"firstName": "Juan",
"lastName": "Pérez",
"isNewUser": false
},
"tokens": {
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"refreshToken": "eyJhbGciOiJSUzI1NiIs...",
"expiresIn": 900,
"tokenType": "Bearer"
},
"redirectTo": "/dashboard"
}
}
```
**Errors:**
| Code | Error | Descripción |
|------|-------|-------------|
| 400 | INVALID_STATE | State token inválido |
| 400 | CODE_EXPIRED | Código de autorización expirado |
| 502 | PROVIDER_ERROR | Error con el proveedor OAuth |
---
### DELETE /auth/oauth/:provider
Desvincular proveedor OAuth.
**Request:**
```http
DELETE /api/v1/auth/oauth/github
Authorization: Bearer {accessToken}
```
**Response 200:**
```json
{
"success": true,
"message": "GitHub desvinculado exitosamente"
}
```
**Errors:**
| Code | Error | Descripción |
|------|-------|-------------|
| 400 | LAST_AUTH_METHOD | No puedes eliminar tu único método de auth |
| 404 | PROVIDER_NOT_LINKED | Proveedor no vinculado |
---
### POST /auth/phone/send
Enviar OTP por SMS o WhatsApp.
**Request:**
```http
POST /api/v1/auth/phone/send
Content-Type: application/json
{
"phone": "+525512345678",
"channel": "whatsapp"
}
```
**Response 200:**
```json
{
"success": true,
"message": "Código enviado a tu WhatsApp",
"data": {
"expiresAt": "2025-12-05T10:05:00Z",
"retryAfter": 60
}
}
```
**Errors:**
| Code | Error | Descripción |
|------|-------|-------------|
| 400 | INVALID_PHONE | Número de teléfono inválido |
| 429 | RATE_LIMIT | Demasiadas solicitudes |
| 502 | SMS_ERROR | Error al enviar mensaje |
---
### POST /auth/phone/verify
Verificar OTP y autenticar.
**Request:**
```http
POST /api/v1/auth/phone/verify
Content-Type: application/json
{
"phone": "+525512345678",
"code": "123456"
}
```
**Response 200:**
```json
{
"success": true,
"data": {
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"phone": "+525512345678",
"firstName": "Usuario",
"lastName": "Nuevo",
"isNewUser": true
},
"tokens": {
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"refreshToken": "eyJhbGciOiJSUzI1NiIs...",
"expiresIn": 900,
"tokenType": "Bearer"
}
}
}
```
**Errors:**
| Code | Error | Descripción |
|------|-------|-------------|
| 401 | INVALID_CODE | Código incorrecto |
| 401 | CODE_EXPIRED | Código expirado |
| 429 | TOO_MANY_ATTEMPTS | Demasiados intentos |
---
### POST /auth/2fa/setup
Generar secreto TOTP para configuración.
**Request:**
```http
POST /api/v1/auth/2fa/setup
Authorization: Bearer {accessToken}
```
**Response 200:**
```json
{
"success": true,
"data": {
"secret": "JBSWY3DPEHPK3PXP",
"qrCode": "data:image/png;base64,iVBORw0KGgo...",
"otpauthUrl": "otpauth://totp/OrbiQuant:usuario@example.com?..."
}
}
```
---
### POST /auth/2fa/enable
Activar 2FA después de verificar código.
**Request:**
```http
POST /api/v1/auth/2fa/enable
Authorization: Bearer {accessToken}
Content-Type: application/json
{
"code": "123456"
}
```
**Response 200:**
```json
{
"success": true,
"message": "2FA activado exitosamente",
"data": {
"backupCodes": [
"A1B2C3D4",
"E5F6G7H8",
"I9J0K1L2",
"M3N4O5P6",
"Q7R8S9T0",
"U1V2W3X4",
"Y5Z6A7B8",
"C9D0E1F2",
"G3H4I5J6",
"K7L8M9N0"
]
}
}
```
---
### POST /auth/2fa/verify
Verificar código 2FA durante login.
**Request:**
```http
POST /api/v1/auth/2fa/verify
Content-Type: application/json
{
"tempToken": "temp_token_from_login",
"code": "123456"
}
```
**Response 200:**
```json
{
"success": true,
"data": {
"user": { ... },
"tokens": {
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"refreshToken": "eyJhbGciOiJSUzI1NiIs...",
"expiresIn": 900,
"tokenType": "Bearer"
}
}
}
```
---
### POST /auth/2fa/disable
Desactivar 2FA.
**Request:**
```http
POST /api/v1/auth/2fa/disable
Authorization: Bearer {accessToken}
Content-Type: application/json
{
"code": "123456"
}
```
**Response 200:**
```json
{
"success": true,
"message": "2FA desactivado exitosamente"
}
```
---
### POST /auth/forgot-password
Solicitar recuperación de contraseña.
**Request:**
```http
POST /api/v1/auth/forgot-password
Content-Type: application/json
{
"email": "usuario@example.com"
}
```
**Response 200:**
```json
{
"success": true,
"message": "Si el email existe, recibirás instrucciones para recuperar tu contraseña"
}
```
---
### POST /auth/reset-password
Cambiar contraseña con token de recuperación.
**Request:**
```http
POST /api/v1/auth/reset-password
Content-Type: application/json
{
"token": "reset_token_from_email",
"password": "NewSecurePass123!"
}
```
**Response 200:**
```json
{
"success": true,
"message": "Contraseña actualizada exitosamente"
}
```
---
### POST /auth/verify-email
Verificar email con token.
**Request:**
```http
POST /api/v1/auth/verify-email
Content-Type: application/json
{
"token": "verification_token_from_email"
}
```
**Response 200:**
```json
{
"success": true,
"message": "Email verificado exitosamente"
}
```
---
### GET /auth/sessions
Listar sesiones activas.
**Request:**
```http
GET /api/v1/auth/sessions
Authorization: Bearer {accessToken}
```
**Response 200:**
```json
{
"success": true,
"data": {
"sessions": [
{
"id": "session-uuid-1",
"device": {
"type": "desktop",
"browser": "Chrome",
"browserVersion": "120.0.0",
"os": "Windows",
"osVersion": "11"
},
"location": {
"city": "Ciudad de México",
"country": "México",
"countryCode": "MX"
},
"ipAddress": "189.xxx.xxx.xxx",
"lastActivity": "2025-12-05T10:00:00Z",
"createdAt": "2025-12-01T08:00:00Z",
"isCurrent": true
},
{
"id": "session-uuid-2",
"device": {
"type": "mobile",
"browser": "Safari",
"os": "iOS",
"osVersion": "17.1"
},
"location": {
"city": "Guadalajara",
"country": "México"
},
"ipAddress": "187.xxx.xxx.xxx",
"lastActivity": "2025-12-04T15:30:00Z",
"createdAt": "2025-11-28T10:00:00Z",
"isCurrent": false
}
],
"totalCount": 2
}
}
```
---
### DELETE /auth/sessions/:id
Revocar sesión específica.
**Request:**
```http
DELETE /api/v1/auth/sessions/session-uuid-2
Authorization: Bearer {accessToken}
```
**Response 200:**
```json
{
"success": true,
"message": "Sesión cerrada exitosamente"
}
```
---
### DELETE /auth/sessions
Revocar todas las demás sesiones.
**Request:**
```http
DELETE /api/v1/auth/sessions
Authorization: Bearer {accessToken}
```
**Response 200:**
```json
{
"success": true,
"message": "Todas las demás sesiones han sido cerradas",
"data": {
"revokedCount": 3
}
}
```
---
## Formato de Errores
Todos los errores siguen el formato estándar:
```json
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Descripción legible del error",
"details": {
"field": "Detalle específico del campo si aplica"
}
}
}
```
---
## Rate Limiting Headers
```http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1701792060
```
---
## Referencias
- [OpenAPI Spec](../../../98-standards/openapi/auth.yaml)
- [Postman Collection](../../../96-quick-reference/postman/OrbiQuant-Auth.json)