Skip to main content

Flujo de Autenticación

Esta guía explica en detalle cómo funciona el proceso de autenticación con Camarauth SDK, desde que el usuario hace click hasta que está autenticado.

Diagrama de Secuencia

Fase 1: Generación del PIN

1. Usuario inicia el proceso

El usuario hace click en “Iniciar sesión” en la aplicación frontend.

2. Frontend solicita PIN

// React Component
const { generate } = usePinAuth({
  apiUrl: 'http://localhost:3001',
  whatsappNumber: '+34600123456'
});

// Al hacer click
await generate();
Internamente, esto:
  1. Genera un PIN aleatorio (ej: ABC123)
  2. Codifica el PIN en emojis (ej: 🎉🔥✨)
  3. Crea un link de WhatsApp
  4. Genera un código QR

3. Backend registra el PIN

// Backend recibe vía WebSocket
socket.emit('register-pin', {
  pin: 'ABC123',
  emojiString: '🎉🔥✨'
});

// Backend guarda en DB
{
  id: 'uuid',
  pin: 'ABC123',
  emojiString: '🎉🔥✨',
  status: 'pending',
  expiresAt: Date.now() + (3 * 60 * 1000), // 3 minutos
  socketId: 'socket-id'
}

4. Frontend muestra al usuario

// El usuario ve:
<div>
  <img src={qrCodeUrl} alt="Escanea para WhatsApp" />
  <div>Tu código: 🎉 🔥 ✨</div>
  <a href={whatsappLink}>Abrir WhatsApp</a>
  <div>Expira en: 02:59</div>
</div>

Fase 2: Verificación por WhatsApp

5. Usuario envía el PIN

El usuario abre WhatsApp (escaneando el QR o haciendo click en el link) y envía los emojis al número de negocio.

6. Evolution API recibe el mensaje

Evolution API (conectada a tu instancia de WhatsApp Business) detecta el mensaje entrante.

7. Webhook al backend

Evolution API envía un webhook a tu backend:
{
  "event": "messages.upsert",
  "instance": "mi-instancia",
  "data": {
    "key": {
      "remoteJid": "34600123456@s.whatsapp.net",
      "fromMe": false
    },
    "pushName": "Juan Pérez",
    "message": {
      "conversation": "🎉🔥✨"
    }
  }
}

8. Backend decodifica y verifica

// Backend extrae los emojis
const emojiString = '🎉🔥✨';

// Decodifica a PIN
const pin = decodeEmojis(emojiString); // 'ABC123'

// Busca en la base de datos
const pinData = await db.query(
  'SELECT * FROM pins WHERE pin = $1 AND status = $2',
  [pin, 'pending']
);

// Verifica que no haya expirado
if (pinData.expiresAt < Date.now()) {
  throw new Error('PIN_EXPIRED');
}

Fase 3: Autenticación Exitosa

9. Buscar usuario

El backend busca el usuario asociado al número de teléfono:
const user = await db.query(
  'SELECT * FROM users WHERE telefono = $1',
  [phoneNumber]
);

10. Generar tokens JWT

// Access token (15 minutos)
const token = jwt.sign(
  { userId: user.id, roles: user.roles },
  JWT_SECRET,
  { expiresIn: '15m' }
);

// Refresh token (7 días)
const refreshToken = jwt.sign(
  { userId: user.id, type: 'refresh' },
  JWT_SECRET,
  { expiresIn: '7d' }
);

11. Notificar al frontend

// Backend envía vía WebSocket
io.to(socketId).emit('auth-success', {
  success: true,
  verified: true,
  token,
  refreshToken,
  user: {
    id: user.id,
    name: user.nombre,
    phone: user.telefono,
    roles: user.roles
  }
});

12. Frontend autentica al usuario

// Hook usePinAuth recibe el evento
socket.on('auth-success', async (response) => {
  if (response.verified && response.token) {
    // Guardar tokens
    await storage.save({
      token: response.token,
      refreshToken: response.refreshToken,
      user: response.user
    });
    
    // Actualizar estado
    setUser(response.user);
    setStatus('success');
    
    // Callback de éxito
    onSuccess?.(response.user);
  }
});

13. Redirigir al dashboard

// En tu componente
if (status === 'success') {
  return <Navigate to="/dashboard" />;
}

// O muestra mensaje de bienvenida
return (
  <div>
    <h1>¡Bienvenido, {user.name}!</h1>
    <button onClick={logout}>Cerrar sesión</button>
  </div>
);

Refresh Token

Cuando el access token expira (15 minutos), se usa el refresh token para obtener uno nuevo:

Logout

Estados del PIN

Consideraciones de Seguridad

  • Los PINs expiran en 3 minutos por defecto
  • Solo se puede usar una vez
  • Rate limiting evita fuerza bruta
  • Tokens JWT tienen expiración corta (15 min)
  • Refresh tokens rotan en cada uso

Para Desarrolladores

Debugging

Para debuggear el flujo:
// Backend: logs detallados
backend.on('auth:verified', (data) => {
  console.log('Auth verified:', data);
});

// Frontend: logs de socket
socket.on('connect', () => {
  console.log('Socket connected');
});

socket.on('pin-registered', (data) => {
  console.log('PIN registered:', data);
});

socket.on('auth-success', (data) => {
  console.log('Auth success:', data);
});

Testing

// Simular flujo completo en tests
const pin = await generatePin();
await registerPin(pin);
await simulateWebhook(pin); // Simular mensaje de WhatsApp
const auth = await waitForAuth();
expect(auth.token).toBeDefined();