Obtener el estado de inicio de sesión de un usuario

GET /v1/users/{user_id}/sign-in-state · permiso users:read

Devuelve lo que su equipo de soporte necesita cuando un usuario no puede iniciar sesión: los bloqueos de cuenta abiertos del usuario, los recuentos de fallos que siguen activos en cada ruta de inicio de sesión y la última autenticación correcta. La llamada solo lee; no se modifica nada ni se escribe ningún registro de auditoría. Para eliminar los bloqueos, use POST /v1/users/{user_id}:unlock.

La respuesta nunca incluye el identificador interno del contador, una dirección de correo electrónico, una dirección IP, un dispositivo ni un identificador de sesión. Para las sesiones del usuario, use GET /v1/users/{user_id}/sessions.

Alcance de la organización

Envíe org_id para generar una vista de diagnóstico de miembros para un administrador de la organización. La clave también necesita el permiso organizations:read; sin él, la solicitud falla con 403 insufficient_permissions antes de leer nada. Si el usuario no es miembro de esa organización (sin membresía invited, active o suspended), la solicitud falla con 404 not_found, la misma respuesta que para un usuario desconocido. Si el usuario es miembro, last_sign_in procede solo de las sesiones en el contexto de esa organización, y failures siempre es un array vacío, porque los contadores de fallos no se atribuyen a ninguna organización. Los bloqueos se siguen devolviendo, ya que un bloqueo detiene el inicio de sesión de la cuenta en todos los contextos. Sin org_id, la respuesta no cambia.

Solicitud

Parámetro En Obligatorio Descripción
user_id path sí Identificador del usuario, con el prefijo usr_.
org_id query no Identificador de la organización, con el prefijo org_. Limita la vista a esa organización; consulte Alcance de la organización. Requiere organizations:read.

Respuesta

200 OK.

{
  "locked": true,
  "locked_until": "2026-10-20T10:00:00Z",
  "locks": [
    {"id": "lck_0a1b2c3d4e5f6g7h8j9k0m1n2p", "path": "password",
     "locked_at": "2026-10-20T09:45:00Z", "expires_at": "2026-10-20T10:00:00Z"}
  ],
  "failures": [
    {"path": "totp", "count": 3, "window_ends_at": "2026-10-20T09:55:00Z"}
  ],
  "last_sign_in": {"authenticated_at": "2026-10-19T18:12:04Z", "amr": ["pwd", "otp"], "country": "DE"}
}
Campo Descripción
locked true cuando al menos una ruta de inicio de sesión está bloqueada.
locked_until Cuándo termina el último bloqueo abierto; null si no hay ningún bloqueo.
locks Bloqueos abiertos, del más antiguo al más reciente, con como máximo uno por ruta (password, totp, sms_2fa, email_2fa, otp, recovery_code).
failures Intentos fallidos desde el último éxito o el último bloqueo, por ruta, mientras sigue activa la ventana de recuento. Después de window_ends_at, el recuento vuelve a empezar. La ventana de contraseña es brute_force.window_minutes del entorno.
last_sign_in La autenticación correcta más reciente entre las sesiones que aún se conservan: authenticated_at (una nueva autenticación en la misma sesión la adelanta), los métodos de autenticación (amr, RFC 8176) y el último país conocido de la sesión (null si se desconoce). null cuando no se conserva ninguna sesión: el usuario nunca inició sesión, o la última sesión terminó hace más de 30 días.

Errores

Cada error es un cuerpo application/problem+json con un code estable.

HTTP code Cuándo
404 not_found El usuario no existe en este entorno (o el identificador tiene un formato incorrecto), o se indica org_id y el usuario no es miembro de esa organización.
401 unauthenticated Falta la clave de API, no es válida o ha sido revocada.
403 insufficient_permissions La clave no tiene el permiso users:read, o se indica org_id y la clave no tiene organizations:read.
429 rate_limited Se superó el límite de uso; respete Retry-After.
503 service_unavailable Una dependencia no está disponible temporalmente; reintente más tarde.

Ejemplo

curl https://api.eu.keenauth.com/v1/users/usr_0a1b2c3d4e5f6g7h8j9k0m1n2p/sign-in-state \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"

CLI: keenauth users sign-in-state usr_0a1b2c3d4e5f6g7h8j9k0m1n2p