
# List a user's consents

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

Lists the OAuth consents the user has granted to applications, newest first. Only active consents are returned: a consent that was revoked, or replaced by a newer consent of the same application, is not listed. The list pages forward only and returns no total count. The response does not include the text of the consent screen the user saw.

## Request

| Parameter | In | Required | Description |
|---|---|---|---|
| `user_id` | path | yes | User id, prefixed `usr_`. |
| `limit` | query | no | Items per page, 1-100 (default 20). |
| `after` | query | no | Cursor from `list_metadata.after` of the previous page of the same user. |

`before` and `order=asc` are not supported and return `422`.

## Response

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

```json
{
  "data": [
    {
      "id": "cns_01jb2k8m5c3f6t9w2y4b7d0g3k",
      "user_id": "usr_0a1b2c3d4e5f6g7h8j9k0m1n2p",
      "application_id": "app_0a1b2c3d4e5f6g7h8j9k0m1n2p",
      "api_id": "api_0a1b2c3d4e5f6g7h8j9k0m1n2p",
      "org_id": null,
      "scopes": ["openid", "profile", "orders:read"],
      "authorization_details_types": [],
      "granted_at": "2026-10-20T09:00:00Z",
      "consent_screen_version": "3",
      "locale": "en",
      "prompt_reason": "scope_expansion"
    }
  ],
  "list_metadata": {"before": null, "after": null}
}
```

| Field | Description |
|---|---|
| `id` | Consent id, prefixed `cns_`. |
| `application_id` | The application the consent was granted to. |
| `api_id` | The API the consent is bound to, if any. |
| `org_id` | The organization context the consent was granted in, if any. |
| `scopes` | The granted scopes, sorted and unique. |
| `authorization_details_types` | Granted rich authorization request types; empty when none. |
| `consent_screen_version`, `locale` | The version and language of the consent screen the user accepted. |
| `prompt_reason` | Why consent was asked: `first`, `scope_expansion`, `prompt_consent` or `skip_consent` (first-party application without a consent screen). |

## Errors

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

| HTTP | `code` | When |
|---|---|---|
| 400 | `invalid_cursor` | The cursor is malformed or belongs to another list. |
| 422 | `validation_failed` | `limit` is out of range, or `before` or an ascending `order` was sent. |
| 404 | `not_found` | The user does not exist in this environment (or the id is malformed). |
| 401 | `unauthenticated` | The API key is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The key lacks the `users:read` permission. |
| 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/consents?limit=50" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
```

CLI: `keenauth users consents list usr_0a1b2c3d4e5f6g7h8j9k0m1n2p --limit 50`

## Personal data

This endpoint carries personal data: consent records. [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.
