
# List a user's sessions

`GET /v1/users/{user_id}/sessions` · permission `sessions:read`

Lists the user's sessions on a single page, most recently seen first, at most 1,000. The list has no `limit`, `after`, `before` or `order`, and `list_metadata` is always `null`-valued. By default only active sessions are returned; with `include_inactive=true` expired and revoked sessions (still within retention) are returned too. The full IP address is shown and every view is written to the management audit log. Cookies, tokens and device fingerprints are never returned.

## 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 sessions opened under that organization's policy (sessions whose `org_id` is that organization) are returned; the user's sessions in the context of another organization, or outside any organization, are never returned. `ip_address` and `user_agent` are `null` in this view. Without `org_id` the response is unchanged.

## Request

| Parameter | In | Required | Description |
|---|---|---|---|
| `user_id` | path | yes | User id, prefixed `usr_`. |
| `include_inactive` | query | no | `true` to also return expired and revoked sessions. Defaults to `false`. |
| `org_id` | query | no | Organization id, prefixed `org_`. Limits the view to that organization; see [Organization scope](#organization-scope). Needs `organizations:read`. |

## Response

`200 OK`. Empty fields are `null`.

```json
{
  "data": [
    {
      "id": "ses_0a1b2c3d4e5f6g7h8j9k0m1n2p",
      "user_id": "usr_0a1b2c3d4e5f6g7h8j9k0m1n2p",
      "status": "active",
      "login_host": "login.example.com",
      "auth_time": "2026-02-01T08:00:00Z",
      "acr": "mfa",
      "amr": ["pwd", "otp"],
      "created_at": "2026-02-01T08:00:00Z",
      "last_seen_at": "2026-02-01T09:15:00Z",
      "idle_expires_at": "2026-02-08T09:15:00Z",
      "absolute_expires_at": "2026-03-03T08:00:00Z",
      "org_id": null,
      "ip_address": "203.0.113.10",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0)",
      "revoked_at": null,
      "revoke_reason": null
    }
  ],
  "list_metadata": {
    "before": null,
    "after": null
  }
}
```

`status`: `active`, `expired`, `revoked` · `acr`: `1fa`, `mfa`, `phr` · `org_id`: the session's organization, if any.

## Errors

Every error is an `application/problem+json` body with a stable `code`.

| HTTP | `code` | When |
|---|---|---|
| 422 | `validation_failed` | `include_inactive` is not `true` or `false`. |
| 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 `sessions: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

```bash
curl "https://api.eu.keenauth.com/v1/users/usr_0a1b2c3d4e5f6g7h8j9k0m1n2p/sessions?include_inactive=true" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
```

CLI: `keenauth users sessions list usr_0a1b2c3d4e5f6g7h8j9k0m1n2p --include-inactive`

## Personal data

This endpoint carries personal data: sessions. [Personal data in the KeenAuth APIs](/docs/policies/personal-data) 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.
