Autenticación
Login, JWT, segundo factor (OTP) y cambio de password
Kelova usa autenticación por email + password, con JWT como token de sesión. Los usuarios con verificación en dos pasos (otp_required) hacen un paso adicional de OTP antes de recibir el token.
Login
curl -X POST https://api.kelova.app/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@tuempresa.com",
"password": "tu-password"
}'Respuesta — sin segundo factor (200):
{
"token": "eyJhbGciOiJIUzI1NiIs..."
}Respuesta — con segundo factor activo (200): Kelova envía un OTP de 6 dígitos por email y responde sin token todavía.
{
"requires_otp": true,
"email": "admin@tuempresa.com"
}Completa el login con el OTP recibido:
curl -X POST https://api.kelova.app/auth/login/verify-otp \
-H "Content-Type: application/json" \
-d '{
"email": "admin@tuempresa.com",
"otp": "482913"
}'{
"token": "eyJhbGciOiJIUzI1NiIs..."
}Si tu cuenta tiene el segundo factor activo, POST /auth/otp/verify (login passwordless) queda bloqueado — responde 403 TWO_FACTOR_REQUIRED. Debes usar el flujo de arriba: password primero, OTP después.
Usar el token
Incluye el JWT en cada request autenticado:
curl https://api.kelova.app/tenants/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Estructura del JWT
El token codifica el usuario, el tenant y el rol — no necesitas enviar tenant_id en ningún request, el backend lo extrae del token:
{
"sub": "user-uuid",
"email": "admin@tuempresa.com",
"tenant_id": "tenant-uuid",
"tenant_slug": "tuempresa",
"role": "admin",
"exp": 1234567890
}Roles posibles: admin, member, viewer, api_user. El token expira 8 horas después de emitido — no hay refresh token; el cliente vuelve a hacer login.
Cambiar el password
Requiere JWT. Verifica el password actual antes de aceptar el nuevo.
curl -X PUT https://api.kelova.app/auth/change-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"current_password": "password-actual",
"new_password": "password-nuevo-min-8-chars"
}'{
"message": "password changed"
}Recuperar acceso (password olvidado)
Flujo de dos pasos, sin autenticación previa:
Solicita el código. Siempre responde 200, incluso si el email no existe (evita enumeración de cuentas).
curl -X POST https://api.kelova.app/auth/forgot-password \
-H "Content-Type: application/json" \
-d '{"email": "admin@tuempresa.com"}'Resetea el password con el OTP recibido por email.
curl -X POST https://api.kelova.app/auth/reset-password \
-H "Content-Type: application/json" \
-d '{
"email": "admin@tuempresa.com",
"otp": "482913",
"password": "password-nuevo-min-8-chars"
}'{
"message": "password reset — you can now log in"
}OTP genérico
POST /auth/otp/send y POST /auth/otp/verify son los endpoints base de OTP, usados internamente por signup y reset. Body de send: {"email": "...", "purpose": "login|signup|reset_password"}. verify acepta {"email": "...", "code": "...", "purpose": "..."} y — para purpose=login sin segundo factor — devuelve directamente {"token": "..."}.
Todos los endpoints de OTP y password aplican rate limiting por IP y por email, y bloquean tras varios intentos fallidos consecutivos. Un 429 TOO_MANY_REQUESTS es la señal de que debes esperar antes de reintentar — ver Errores.