Skip to main content

Verificar Email de Registro

Paso 2 del proceso de registro: verificar el código de 6 dígitos enviado al email para confirmar la propiedad de la cuenta.


Información General

Este endpoint es el Paso 2 del proceso de registro v1. Verifica el código de 6 dígitos enviado al email del usuario para confirmar que el email es válido y accesible por el usuario.

POST/auth/register/verify?token={token}

Verifica el código de verificación enviado por email y habilita al usuario para completar el registro con su contraseña

📋 Parámetros

tokenstringrequerido

Token de sesión UUID obtenido en el Paso 1 del registro

codestringrequerido

Código de 6 dígitos numéricos recibido por email

📤 Respuesta

{
"code": 3001,
"message": "Email verified successfully",
"data": null
}

Validaciones

Código de Verificación

  • Debe ser exactamente 6 dígitos numéricos
  • No se permiten letras ni caracteres especiales
  • Es sensible a cada dígito (no es case-sensitive porque solo son números)
  • Regex de validación: /^\\d{6}$/

Token de Sesión

  • Debe ser un token UUID válido obtenido en el Paso 1
  • Tiene una validez de 10 minutos desde su emisión
  • Debe existir en Redis con los datos de sesión correspondientes
  • No debe haber sido verificado previamente

Respuestas

Respuesta Exitosa

Email Verificado Exitosamente

Código 3001 - El código de verificación es correcto y el email ha sido confirmado.

{
"code": 3001,
"message": "Email verified successfully",
"data": null
}

Siguiente paso: Después de esta respuesta, el usuario puede proceder al Paso 3: completar el registro estableciendo su contraseña.

Cambios en el sistema:

  • Se marca el token como verificado en Redis
  • Se establece la clave verify:{token} con valor 'true'
  • El token permanece válido por 10 minutos para el Paso 3

Errores

Datos Faltantes o Inválidos

Código 4006 - Faltan campos requeridos o el formato del código es inválido.

{
"code": 4006,
"message": "Missing required data"
}

Causas posibles:

  • No se proporcionó el código en el body
  • El código no tiene exactamente 6 dígitos
  • No se proporcionó el token en query params
  • El formato del código incluye caracteres no numéricos

Token de Sesión Inválido

Código 4015 - El token de sesión no existe, expiró o es inválido.

{
"code": 4015,
"message": "Invalid session token"
}

Causas posibles:

  • El token expiró (más de 10 minutos desde el Paso 1)
  • Token malformado o no válido
  • La sesión fue eliminada de Redis
  • Token usado en una verificación anterior

Solución: El usuario debe reiniciar el proceso de registro desde el Paso 1.

Código de Verificación Incorrecto

Código 4005 - El código proporcionado no coincide con el código enviado.

{
"code": 4005,
"message": "Invalid verification code"
}

Causas posibles:

  • Código ingresado incorrectamente
  • Código de un email anterior (si se solicitó reenvío)
  • Typo en algún dígito

Solución:

  • Verificar el email nuevamente
  • Solicitar reenvío del código si es necesario
  • Intentar nuevamente con el código correcto

Token de Verificación Inválido

Código 4004 - El token de verificación interno no existe o expiró.

{
"code": 4004,
"message": "The verification token is invalid"
}

Causas posibles:

  • El código de verificación expiró en Redis
  • La sesión de verificación fue limpiada
  • Error interno del sistema

Solución: Solicitar un nuevo código usando el endpoint de reenvío.


Ejemplos de Implementación

JavaScript/TypeScript

const verifyRegistrationEmail = async (token, code) => {
try {
const response = await fetch(
`https://api.swapbits.co/auth/register/verify?token=${token}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ code })
}
);

const result = await response.json();

if (result.code === 3001) {
console.log('Email verificado exitosamente');
// Redirigir al paso 3: establecer contraseña
return {
success: true,
message: 'Email verificado. Ahora establece tu contraseña.'
};
} else if (result.code === 4005) {
console.error('Código incorrecto');
return {
success: false,
error: 'INVALID_CODE',
message: 'El código ingresado es incorrecto. Intenta nuevamente.'
};
} else if (result.code === 4015) {
console.error('Sesión expirada');
return {
success: false,
error: 'SESSION_EXPIRED',
message: 'Tu sesión ha expirado. Reinicia el registro.'
};
} else if (result.code === 4004) {
console.error('Código expirado');
return {
success: false,
error: 'CODE_EXPIRED',
message: 'El código ha expirado. Solicita uno nuevo.'
};
}

return { success: false, error: result.message };
} catch (error) {
console.error('Error verificando email:', error);
return { success: false, error: error.message };
}
};

// Validación del código en el frontend
const validateCode = (code) => {
const regex = /^\d{6}$/;
return regex.test(code);
};

// Uso
const token = sessionStorage.getItem('registrationToken');
const code = '123456';

if (validateCode(code)) {
const result = await verifyRegistrationEmail(token, code);
if (result.success) {
// Mostrar formulario de contraseña
showPasswordForm();
} else {
// Mostrar error al usuario
showError(result.message);
}
} else {
console.error('Formato de código inválido');
}

TypeScript con manejo de tipos

interface VerifyEmailResponse {
code: number;
message: string;
data: null;
}

interface VerifyResult {
success: boolean;
error?: string;
message?: string;
}

const verifyRegistrationEmail = async (
token: string,
code: string
): Promise<VerifyResult> => {
// Validación previa
if (!/^\d{6}$/.test(code)) {
return {
success: false,
error: 'INVALID_FORMAT',
message: 'El código debe tener exactamente 6 dígitos'
};
}

try {
const response = await fetch(
`https://api.swapbits.co/auth/register/verify?token=${token}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ code }),
}
);

const result: VerifyEmailResponse = await response.json();

switch (result.code) {
case 3001:
return {
success: true,
message: 'Email verificado exitosamente'
};
case 4005:
return {
success: false,
error: 'INVALID_CODE',
message: 'Código incorrecto'
};
case 4015:
return {
success: false,
error: 'SESSION_EXPIRED',
message: 'Sesión expirada'
};
case 4004:
return {
success: false,
error: 'CODE_EXPIRED',
message: 'Código expirado'
};
default:
return {
success: false,
error: 'UNKNOWN',
message: result.message
};
}
} catch (error) {
return {
success: false,
error: 'NETWORK_ERROR',
message: error instanceof Error ? error.message : 'Error de red'
};
}
};

// Componente de ejemplo con manejo de estados
const VerificationForm = () => {
const [code, setCode] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);

const handleVerify = async () => {
setLoading(true);
setError(null);

const token = sessionStorage.getItem('registrationToken');
if (!token) {
setError('No se encontró el token de sesión');
setLoading(false);
return;
}

const result = await verifyRegistrationEmail(token, code);

if (result.success) {
// Navegar al siguiente paso
navigate('/register/complete');
} else {
setError(result.message || 'Error desconocido');
}

setLoading(false);
};

return (
<div>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
maxLength={6}
pattern="\d{6}"
placeholder="123456"
/>
<button onClick={handleVerify} disabled={loading || code.length !== 6}>
{loading ? 'Verificando...' : 'Verificar'}
</button>
{error && <div className="error">{error}</div>}
</div>
);
};

Python

import requests
import re

def validate_code_format(code: str) -> bool:
"""Validar formato del código"""
return bool(re.match(r'^\d{6}$', code))

def verify_registration_email(token: str, code: str) -> dict:
"""
Verificar código de email para registro

Args:
token: Token de sesión del paso 1
code: Código de 6 dígitos

Returns:
Resultado de la verificación
"""
# Validación previa
if not validate_code_format(code):
return {
'success': False,
'error': 'INVALID_FORMAT',
'message': 'El código debe tener exactamente 6 dígitos numéricos'
}

url = 'https://api.swapbits.co/auth/register/verify'
params = {'token': token}
data = {'code': code}

try:
response = requests.post(url, params=params, json=data, timeout=10)
result = response.json()

if result['code'] == 3001:
print("Email verificado exitosamente")
return {
'success': True,
'message': 'Email verificado. Procede a establecer tu contraseña.'
}
elif result['code'] == 4005:
print("Código incorrecto")
return {
'success': False,
'error': 'INVALID_CODE',
'message': 'El código ingresado es incorrecto'
}
elif result['code'] == 4015:
print("Sesión expirada")
return {
'success': False,
'error': 'SESSION_EXPIRED',
'message': 'Tu sesión ha expirado. Reinicia el registro.'
}
elif result['code'] == 4004:
print("Código expirado")
return {
'success': False,
'error': 'CODE_EXPIRED',
'message': 'El código ha expirado. Solicita uno nuevo.'
}
elif result['code'] == 4006:
return {
'success': False,
'error': 'MISSING_DATA',
'message': 'Datos faltantes o inválidos'
}
else:
return {
'success': False,
'error': 'UNKNOWN',
'message': result.get('message', 'Error desconocido')
}

except requests.exceptions.RequestException as e:
print(f"Error de conexión: {e}")
return {
'success': False,
'error': 'NETWORK_ERROR',
'message': str(e)
}

# Ejemplo de uso con interfaz CLI
def main():
token = input("Ingresa el token de registro: ")

while True:
code = input("Ingresa el código de 6 dígitos: ")

if not validate_code_format(code):
print("Error: El código debe tener exactamente 6 dígitos")
continue

result = verify_registration_email(token, code)

if result['success']:
print(f"Éxito: {result['message']}")
break
else:
print(f"Error: {result['message']}")

if result['error'] == 'SESSION_EXPIRED':
print("Debes reiniciar el proceso de registro")
break
elif result['error'] == 'CODE_EXPIRED':
retry = input("¿Solicitar nuevo código? (s/n): ")
if retry.lower() != 's':
break
else:
retry = input("¿Intentar nuevamente? (s/n): ")
if retry.lower() != 's':
break

if __name__ == '__main__':
main()

cURL

# Verificación básica
curl -X POST \
'https://api.swapbits.co/auth/register/verify?token=550e8400-e29b-41d4-a716-446655440000' \
-H 'Content-Type: application/json' \
-d '{
"code": "123456"
}'
# Script bash con manejo de respuesta
#!/bin/bash

TOKEN="550e8400-e29b-41d4-a716-446655440000"
CODE="123456"

response=$(curl -s -X POST \
"https://api.swapbits.co/auth/register/verify?token=$TOKEN" \
-H 'Content-Type: application/json' \
-d "{\"code\": \"$CODE\"}")

code=$(echo $response | jq -r '.code')
message=$(echo $response | jq -r '.message')

case $code in
3001)
echo "Éxito: Email verificado"
echo "Procede al paso 3: establecer contraseña"
;;
4005)
echo "Error: Código incorrecto"
;;
4015)
echo "Error: Sesión expirada - Reinicia el registro"
;;
4004)
echo "Error: Código expirado - Solicita uno nuevo"
;;
*)
echo "Error: $message"
;;
esac

Flujo de Verificación

graph TD
A[POST /auth/register/verify] --> B{Validar formato código}
B -->|Inválido| C[Error 4006]
B -->|Válido| D{Token existe?}
D -->|No| E[Error 4015]
D -->|Sí| F{Código de verificación existe?}
F -->|No| G[Error 4004]
F -->|Sí| H{Código coincide?}
H -->|No| I[Error 4005]
H -->|Sí| J[Marcar como verificado]
J --> K[Retornar éxito 3001]
K --> L[Usuario puede proceder al Paso 3]

Manejo de Errores Común

Sistema de Reintentos

const verifyWithRetry = async (token, code, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
console.log(`Intento ${attempt} de ${maxRetries}`);

const result = await verifyRegistrationEmail(token, code);

if (result.success) {
return result;
}

// No reintentar si el error no es recuperable
if (result.error === 'SESSION_EXPIRED' || result.error === 'CODE_EXPIRED') {
return result;
}

// Esperar antes del siguiente intento
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}

return {
success: false,
error: 'MAX_RETRIES',
message: 'Se alcanzó el máximo de intentos'
};
};

Consideraciones de Seguridad

Seguridad del Código de Verificación

Medidas implementadas:

  • Códigos de un solo uso (se invalidan después de verificación exitosa)
  • Expiración de 10 minutos desde la emisión
  • Cooldown de 30 segundos entre reenvíos
  • Validación estricta de formato (solo 6 dígitos numéricos)
  • Los códigos se almacenan en Redis con TTL automático
  • No hay límite de intentos por código (considera implementar rate limiting en producción)

Recomendaciones:

  • Implementar rate limiting por IP/usuario
  • Considerar bloqueo temporal después de múltiples intentos fallidos
  • Registrar intentos de verificación para análisis de seguridad

Notas Importantes

Flujo de Registro Completo

Este endpoint es el Paso 2 de 3 en el proceso de registro v1:

  1. Paso 1: Iniciar Registro - Enviar email
  2. Paso 2: Verificar Email (este endpoint) - Confirmar código
  3. Paso 3: Completar Registro - Establecer contraseña

Después de verificar exitosamente, el usuario tiene 10 minutos para completar el Paso 3 antes de que expire la sesión.

Reenvío de Código

Si el código no llega o expira, utiliza el endpoint de reenvío de código para solicitar un nuevo código.

  • Cooldown de 30 segundos entre reenvíos
  • El nuevo código invalida el anterior
  • Requiere el mismo token de sesión

Probar esta API

¿Quieres probar este endpoint de forma interactiva con tus propios datos?


Enlaces Relacionados