Reenviar Código de Registro
Endpoint para solicitar el reenvío de un nuevo código de verificación de 6 dígitos si el código anterior expiró o no fue recibido durante el proceso de registro.
Información General
Este endpoint permite a los usuarios solicitar un nuevo código de verificación durante el registro v1 sin tener que reiniciar todo el proceso. Implementa un sistema de cooldown para prevenir abuso.
/auth/register/resend?token={token}Genera y envía un nuevo código de verificación al email del usuario, invalidando el código anterior
📋 Parámetros
tokenstringrequeridoToken de sesión UUID obtenido en el Paso 1 del registro
📤 Respuesta
{
"code": 1010,
"message": "Verification code sent successfully",
"data": {
"cooldown": 30
}
}Funcionamiento
Sistema de Cooldown
Para prevenir spam y abuso, el sistema implementa un cooldown de 30 segundos entre solicitudes de reenvío:
- Primera solicitud: Envía código inmediatamente
- Solicitudes subsecuentes: Deben esperar 30 segundos desde la última solicitud
- El cooldown se reinicia con cada reenvío exitoso
- El cooldown es específico por token de sesión
Gestión de Códigos
- Cada nuevo código invalida el código anterior
- El nuevo código tiene una validez de 5 minutos
- Los códigos son de 6 dígitos numéricos
- Se almacenan en Redis con TTL automático
Validaciones
Token de Sesión
- Debe ser un token UUID válido del Paso 1
- Debe existir en Redis con datos de sesión válidos
- No debe haber expirado (10 minutos desde el Paso 1)
- Debe contener información del email del usuario
Sistema de Rate Limiting
- Cooldown de 30 segundos entre reenvíos
- Se verifica mediante clave en Redis:
resend_cooldown:register:{token} - Retorna error 429 si el cooldown está activo
Respuestas
Respuesta Exitosa
Código Reenviado Exitosamente
Protección anti-spam de 30 segundos
El sistema implementa un período de espera obligatorio de 30 segundos entre cada solicitud de reenvío para:
- Prevenir abuso del servicio de email
- Reducir costos de envío
- Evitar saturación de la bandeja del usuario
- Proteger contra ataques de fuerza bruta
Validación de Token
Requisitos del token:
- Debe ser un UUID válido
- Debe estar asociado a una sesión activa
- No debe haber expirado (10 minutos de vida útil)
- Debe corresponder a un proceso de registro iniciado
Respuestas del Sistema
Código Reenviado Exitosamente
Código 1010 - Nuevo código de verificación enviado.
{
"code": 1010,
"message": "Verification code sent successfully",
"data": {
"cooldown": 30
}
}
Comportamiento del sistema:
- Se genera un nuevo código de 6 dígitos
- Se invalida el código anterior
- Se envía email con el nuevo código
- Se activa cooldown de 30 segundos
- El nuevo código expira en 5 minutos
Cooldown Activo
Código 4030 - Debes esperar antes de solicitar otro código.
{
"code": 4030,
"message": "Please wait 30 seconds before requesting another code"
}
El usuario debe esperar el tiempo de cooldown antes de poder solicitar un nuevo código.
Token Inválido o Expirado
Código 4015 - El token de sesión no es válido.
{
"code": 4015,
"message": "Invalid session token"
}
Posibles causas:
- Token expirado (más de 10 minutos)
- Token malformado o corrupto
- Sesión no encontrada en Redis
- Token ya utilizado completamente
Datos Faltantes
Código 4006 - Falta el parámetro token requerido.
{
"code": 4006,
"message": "Missing required data"
}
Ejemplos de Implementación
JavaScript/TypeScript
const resendVerificationCode = async (token) => {
try {
const response = await fetch(
`https://api.swapbits.co/auth/register/resend?token=${token}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}
);
const result = await response.json();
switch (result.code) {
case 1010:
console.log('✓ Nuevo código enviado exitosamente');
console.log(`⏳ Cooldown: ${result.data.cooldown} segundos`);
// Deshabilitar botón de reenvío temporalmente
const resendButton = document.getElementById('resend-button');
resendButton.disabled = true;
resendButton.textContent = `Espera ${result.data.cooldown}s`;
// Reactivar después del cooldown
setTimeout(() => {
resendButton.disabled = false;
resendButton.textContent = 'Reenviar código';
}, result.data.cooldown * 1000);
return { success: true, cooldown: result.data.cooldown };
case 4030:
console.error('❌ Debes esperar antes de solicitar otro código');
return { success: false, error: 'COOLDOWN_ACTIVE' };
case 4015:
console.error('❌ Token inválido o expirado');
return {
success: false,
error: 'INVALID_TOKEN',
message: 'Tu sesión ha expirado, por favor inicia el proceso nuevamente'
};
default:
console.error('❌ Error desconocido:', result.message);
return { success: false, error: result.message };
}
} catch (error) {
console.error('❌ Error de red:', error);
return { success: false, error: error.message };
}
};
// Uso con control de cooldown en UI
const token = sessionStorage.getItem('registrationToken');
resendVerificationCode(token);
Python
import requests
import time
def resend_verification_code(token: str) -> dict:
"""
Reenviar código de verificación con manejo de cooldown
Args:
token: Token UUID de sesión del registro
Returns:
dict: Resultado de la operación con success, cooldown o error
"""
url = f'https://api.swapbits.co/auth/register/resend?token={token}'
try:
response = requests.post(url, timeout=10)
result = response.json()
if result['code'] == 1010:
print(f"✓ Código reenviado exitosamente")
print(f"⏳ Cooldown: {result['data']['cooldown']} segundos")
return {
'success': True,
'cooldown': result['data']['cooldown'],
'message': 'Revisa tu email para el nuevo código'
}
elif result['code'] == 4030:
print("❌ Cooldown activo, debes esperar")
return {
'success': False,
'error': 'COOLDOWN_ACTIVE',
'message': 'Espera 30 segundos antes de solicitar otro código'
}
elif result['code'] == 4015:
print("❌ Token inválido o expirado")
return {
'success': False,
'error': 'INVALID_TOKEN',
'message': 'Tu sesión ha expirado'
}
else:
return {'success': False, 'error': result['message']}
except requests.exceptions.Timeout:
return {'success': False, 'error': 'REQUEST_TIMEOUT'}
except requests.exceptions.RequestException as e:
return {'success': False, 'error': str(e)}
# Ejemplo de uso con retry automático
def resend_with_retry(token: str, max_retries: int = 3) -> dict:
"""Reintentar reenvío automáticamente respetando cooldown"""
for attempt in range(max_retries):
result = resend_verification_code(token)
if result['success']:
return result
if result.get('error') == 'COOLDOWN_ACTIVE':
print(f"Intento {attempt + 1}/{max_retries}: Esperando cooldown...")
time.sleep(30)
continue
# Si es otro error, no reintentar
return result
return {'success': False, 'error': 'MAX_RETRIES_EXCEEDED'}
# Uso
token = 'your-session-token-here'
result = resend_verification_code(token)
cURL
# Solicitar reenvío de código
curl -X POST 'https://api.swapbits.co/auth/register/resend?token=550e8400-e29b-41d4-a716-446655440000' \
-H 'Content-Type: application/json'
# Respuesta exitosa
# {
# "code": 1010,
# "message": "Verification code sent successfully",
# "data": {
# "cooldown": 30
# }
# }
Flujo de Usuario Recomendado
1. Interfaz de Usuario
// Implementación recomendada en el frontend
class CodeResendManager {
constructor(token) {
this.token = token;
this.cooldownActive = false;
this.cooldownRemaining = 0;
}
async resendCode() {
if (this.cooldownActive) {
console.warn('Cooldown activo, por favor espera');
return { success: false, error: 'COOLDOWN_ACTIVE' };
}
const result = await resendVerificationCode(this.token);
if (result.success) {
this.startCooldown(result.cooldown);
}
return result;
}
startCooldown(seconds) {
this.cooldownActive = true;
this.cooldownRemaining = seconds;
const interval = setInterval(() => {
this.cooldownRemaining--;
this.updateUI();
if (this.cooldownRemaining <= 0) {
clearInterval(interval);
this.cooldownActive = false;
this.updateUI();
}
}, 1000);
}
updateUI() {
const button = document.getElementById('resend-button');
const message = document.getElementById('cooldown-message');
if (this.cooldownActive) {
button.disabled = true;
button.textContent = `Reenviar (${this.cooldownRemaining}s)`;
message.textContent = `Puedes solicitar un nuevo código en ${this.cooldownRemaining} segundos`;
} else {
button.disabled = false;
button.textContent = 'Reenviar código';
message.textContent = '¿No recibiste el código?';
}
}
}
// Uso
const manager = new CodeResendManager(sessionStorage.getItem('registrationToken'));
document.getElementById('resend-button').addEventListener('click', () => {
manager.resendCode();
});
2. Manejo de Errores
const handleResendErrors = async (token) => {
const result = await resendVerificationCode(token);
if (!result.success) {
switch (result.error) {
case 'COOLDOWN_ACTIVE':
showNotification('Por favor espera antes de solicitar otro código', 'warning');
break;
case 'INVALID_TOKEN':
showNotification('Tu sesión ha expirado. Reinicia el proceso de registro.', 'error');
// Redirigir al inicio del registro
window.location.href = '/register';
break;
case 'REQUEST_TIMEOUT':
showNotification('Error de conexión. Verifica tu internet.', 'error');
break;
default:
showNotification('Error al reenviar código. Intenta nuevamente.', 'error');
}
} else {
showNotification('Código enviado exitosamente. Revisa tu email.', 'success');
}
};
Casos de Uso Comunes
Código No Recibido
Situación: El usuario no recibe el email con el código.
Solución:
- Verificar carpeta de spam/correo no deseado
- Esperar 1-2 minutos (entrega puede demorar)
- Usar endpoint de reenvío después del cooldown
- Verificar que el email sea correcto
Código Expirado
Situación: El código de 6 dígitos ya expiró (5 minutos).
Solución:
- Solicitar nuevo código con este endpoint
- El código anterior se invalida automáticamente
- Usar el nuevo código dentro de 5 minutos
Múltiples Intentos
Situación: Usuario intenta reenviar múltiples veces rápidamente.
Comportamiento:
- Sistema bloquea con código 4030
- Debe esperar 30 segundos obligatorios
- Protege contra spam y abuso
- Frontend debe deshabilitar botón durante cooldown
TypeScript con UI y Cooldown Timer
import { useState, useEffect } from 'react';
interface ResendResponse {
success: boolean;
cooldown?: number;
error?: string;
message?: string;
}
const ResendCodeButton = ({ token }: { token: string }) => {
const [loading, setLoading] = useState(false);
const [cooldown, setCooldown] = useState(0);
const [message, setMessage] = useState<string | null>(null);
// Countdown timer
useEffect(() => {
if (cooldown > 0) {
const timer = setTimeout(() => {
setCooldown(cooldown - 1);
}, 1000);
return () => clearTimeout(timer);
}
}, [cooldown]);
const resendCode = async (): Promise<ResendResponse> => {
try {
const response = await fetch(
`https://api.swapbits.co/auth/register/resend?token=${token}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
}
);
const result = await response.json();
switch (result.code) {
case 1010:
return {
success: true,
cooldown: result.data.cooldown,
message: 'Nuevo código enviado a tu email'
};
case 4030:
return {
success: false,
error: 'COOLDOWN_ACTIVE',
message: 'Debes esperar antes de solicitar otro código'
};
case 4015:
return {
success: false,
error: 'SESSION_EXPIRED',
message: 'Sesión expirada. Reinicia el registro.'
};
default:
return {
success: false,
error: 'UNKNOWN',
message: result.message
};
}
} catch (error) {
return {
success: false,
error: 'NETWORK_ERROR',
message: 'Error de conexión'
};
}
};
const handleResend = async () => {
setLoading(true);
setMessage(null);
const result = await resendCode();
if (result.success && result.cooldown) {
setCooldown(result.cooldown);
setMessage(result.message || 'Código reenviado');
} else {
setMessage(result.message || 'Error al reenviar código');
// Redirigir si la sesión expiró
if (result.error === 'SESSION_EXPIRED') {
setTimeout(() => {
window.location.href = '/register';
}, 2000);
}
}
setLoading(false);
};
const isDisabled = loading || cooldown > 0;
return (
<div className="resend-container">
<button
onClick={handleResend}
disabled={isDisabled}
className="resend-button"
>
{loading ? (
'Enviando...'
) : cooldown > 0 ? (
`Espera ${cooldown}s`
) : (
'Reenviar código'
)}
</button>
{message && (
<div className={`message ${message.includes('Error') ? 'error' : 'success'}`}>
{message}
</div>
)}
</div>
);
};
export default ResendCodeButton;
cURL con Scripts
# Reenvío básico
curl -X POST \
'https://api.swapbits.co/auth/register/resend?token=550e8400-e29b-41d4-a716-446655440000' \
-H 'Content-Type: application/json'
# Script bash con manejo de cooldown
#!/bin/bash
TOKEN="550e8400-e29b-41d4-a716-446655440000"
resend_code() {
response=$(curl -s -X POST \
"https://api.swapbits.co/auth/register/resend?token=$TOKEN" \
-H 'Content-Type: application/json')
code=$(echo $response | jq -r '.code')
message=$(echo $response | jq -r '.message')
case $code in
1010)
cooldown=$(echo $response | jq -r '.data.cooldown')
echo "Código reenviado exitosamente"
echo "Espera $cooldown segundos antes de solicitar otro"
return 0
;;
4030)
echo "Error: Debes esperar 30 segundos antes de solicitar otro código"
return 1
;;
4015)
echo "Error: Sesión expirada - Reinicia el registro"
return 2
;;
*)
echo "Error: $message"
return 3
;;
esac
}
# Intentar reenvío con manejo de cooldown
echo "Solicitando reenvío de código..."
resend_code
exit_code=$?
if [ $exit_code -eq 1 ]; then
echo "Esperando 30 segundos por cooldown..."
sleep 30
echo "Reintentando..."
resend_code
fi
Flujo de Trabajo
graph TD
A[POST /auth/register/resend] --> B{Token existe?}
B -->|No| C[Error 4006/4015]
B -->|Sí| D{Cooldown activo?}
D -->|Sí| E[Error 4030 - Esperar]
D -->|No| F[Extraer email de sesión]
F --> G[Generar nuevo código 6 dígitos]
G --> H[Guardar código en Redis - 5 min]
H --> I[Invalidar código anterior]
I --> J[Enviar email con nuevo código]
J --> K[Establecer cooldown 30s]
K --> L[Retornar éxito 1010]
Mejores Prácticas
Para Desarrolladores Frontend
// Sistema de gestión de reenvío con UI feedback
class CodeResendManager {
constructor(token) {
this.token = token;
this.cooldownEndTime = null;
this.cooldownInterval = null;
}
async resend() {
if (this.isInCooldown()) {
return {
success: false,
error: 'LOCAL_COOLDOWN',
message: `Espera ${this.getRemainingCooldown()} segundos`
};
}
try {
const response = await fetch(
`https://api.swapbits.co/auth/register/resend?token=${this.token}`,
{ method: 'POST', headers: { 'Content-Type': 'application/json' } }
);
const result = await response.json();
if (result.code === 1010) {
// Iniciar cooldown local
this.startCooldown(result.data.cooldown);
return { success: true, cooldown: result.data.cooldown };
}
return { success: false, error: result.code, message: result.message };
} catch (error) {
return { success: false, error: 'NETWORK', message: error.message };
}
}
startCooldown(seconds) {
this.cooldownEndTime = Date.now() + (seconds * 1000);
// Actualizar UI cada segundo
this.cooldownInterval = setInterval(() => {
const remaining = this.getRemainingCooldown();
if (remaining <= 0) {
this.clearCooldown();
this.onCooldownEnd?.();
} else {
this.onCooldownTick?.(remaining);
}
}, 1000);
}
clearCooldown() {
if (this.cooldownInterval) {
clearInterval(this.cooldownInterval);
this.cooldownInterval = null;
}
this.cooldownEndTime = null;
}
isInCooldown() {
return this.cooldownEndTime && Date.now() < this.cooldownEndTime;
}
getRemainingCooldown() {
if (!this.cooldownEndTime) return 0;
return Math.ceil((this.cooldownEndTime - Date.now()) / 1000);
}
// Callbacks opcionales para actualizar UI
onCooldownTick = null;
onCooldownEnd = null;
}
// Uso
const manager = new CodeResendManager(token);
manager.onCooldownTick = (seconds) => {
document.getElementById('resend-btn').textContent = `Espera ${seconds}s`;
document.getElementById('resend-btn').disabled = true;
};
manager.onCooldownEnd = () => {
document.getElementById('resend-btn').textContent = 'Reenviar código';
document.getElementById('resend-btn').disabled = false;
};
// Reenviar código
const result = await manager.resend();
if (result.success) {
showNotification('Código reenviado. Revisa tu email.');
}
Consideraciones de Seguridad
Protección contra Abuso
Medidas implementadas:
- Cooldown de 30 segundos entre reenvíos
- Los códigos expiran en 5 minutos
- Cada nuevo código invalida el anterior
- La sesión completa expira en 10 minutos
- Rate limiting por token de sesión
Recomendaciones adicionales:
- Implementar rate limiting por IP en el servidor
- Considerar incrementar el cooldown después de múltiples reenvíos
- Registrar patrones sospechosos de reenvíos excesivos
- Implementar CAPTCHA después de cierto número de reenvíos
Manejo de Sesiones
Límites temporales:
- Token de sesión: 10 minutos desde el Paso 1
- Código de verificación: 5 minutos desde la emisión
- Cooldown de reenvío: 30 segundos
Comportamiento:
- Si la sesión expira, el usuario debe reiniciar desde el Paso 1
- Los códigos antiguos se invalidan automáticamente al solicitar reenvío
- El cooldown se reinicia con cada reenvío exitoso
Notas Importantes
Cuándo Usar Este Endpoint
Usa este endpoint cuando:
- El código de verificación no llega al email
- El código expiró (5 minutos)
- El usuario ingresó mal el email y no puede acceder al código
- Se sospecha que el email fue filtrado como spam
No uses este endpoint para:
- Reiniciar el proceso de registro (usa
/auth/registernuevamente) - Cambiar el email de registro (debe reiniciarse todo el proceso)
- Verificar si un código es válido (usa
/auth/register/verify)
Probar esta API
¿Quieres probar este endpoint de forma interactiva con tus propios datos?