List a user's authenticators
GET /v1/users/{user_id}/authenticators · permission users:read
Lists the authenticators (passkeys, TOTP, SMS, email and push factors) of a user in one page, including those revoked in the last 90 days, ordered by creation time. The number of authenticators per user is bounded, so the list has no limit, after, before or order, and list_metadata is always null valued. Only metadata is returned: never public keys, credential ids, TOTP secrets or recovery codes.
Organization scope
Pass org_id to build a member diagnostics view for an organization admin. The key then also needs the organizations:read permission; without it the request fails with 403 insufficient_permissions before anything is read. If the user is not a member of that organization (no invited, active or suspended membership), the request fails with 404 not_found, the same response as for an unknown user. If the user is a member, only the class of each authenticator and whether MFA is enrolled are shown: only active authenticators are listed, and label, last_used_at, revoked_at, revoked_by and revoke_reason are null and synced is false, because the person's device details outside the organization do not belong to it. MFA is enrolled when an active authenticator has the role second_factor or both. Without org_id the response is unchanged.
Request
| Parameter | In | Required | Description |
|---|---|---|---|
user_id |
path | yes | User id, prefixed usr_. |
org_id |
query | no | Organization id, prefixed org_. Limits the view to that organization; see Organization scope. Needs organizations:read. |
Response
200 OK. data holds the authenticators ordered by creation time; list_metadata is always null valued because the list is not paginated. Empty fields are null.
When the key lacks the users:read_pii permission, label is reduced to initials (A. L.).
{
"data": [
{
"id": "cred_0a1b2c3d4e5f6g7h8j9k0m1n2p",
"type": "webauthn",
"role": "both",
"label": "Laptop",
"status": "active",
"synced": true,
"created_at": "2026-01-15T09:30:00Z",
"last_used_at": "2026-02-01T08:00:00Z",
"revoked_at": null,
"revoked_by": null,
"revoke_reason": null
}
],
"list_metadata": {
"before": null,
"after": null
}
}
type: webauthn, totp, sms, email, push · role: first_factor, second_factor, both · status: pending, active, revoked, clone_suspected
Errors
Every error is an application/problem+json body with a stable code.
| HTTP | code |
When |
|---|---|---|
| 404 | not_found |
The user does not exist in this environment (or the id is malformed), or org_id is given and the user is not a member of that organization. |
| 401 | unauthenticated |
The API key is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The key lacks the users:read permission, or org_id is given and the key lacks organizations:read. |
| 429 | rate_limited |
The rate limit was exceeded; honor Retry-After. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry later. |
Example
curl https://api.eu.keenauth.com/v1/users/usr_0a1b2c3d4e5f6g7h8j9k0m1n2p/authenticators \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
Personal data
This endpoint carries personal data: credentials. Personal data in the KeenAuth APIs describes what is stored, how long it is kept and how it is deleted. Do not send special categories of personal data (health, biometric data, religion, political opinions, sexual orientation) in any field.