Files
bookhoard/docs/developer/api/admin/list_users.md
T
John O'Keefe 0c45137f5b docs(users): live-smoke correction — GET /api/auth/users emits sqlc ListUsersRow, no password_hash
Curated smoke run of the generated collection against the live dev
server (37/37 after fixes): registration matrix (409 duplicate email,
403 admin-creation-with-admins-present, 400 weak password), non-admin
403s, device-token/opds 401s, collection CRUD incl. the documented 201
update quirk and 204 delete, stats routes, scanner, jobs, malformed-uuid
400s. Testuser untouched (password test uses a guaranteed-wrong current
password -> 401); the smoke user was admin-deleted in cleanup and its
token verified dead.

Correction the smoke run forced: the batch-8 'password_hash leak' was a
false alarm — my registry pin ([]database.Users) never matched the
handler, which returns []database.ListUsersRow (sqlc join with
device_count). Live response confirmed: id/email/username/theme/names/
role/max_devices/created_at/updated_at/device_count — NO hash. Doc
example, field table, and registry pin all corrected; leak note
replaced with the live-verified statement.

Also verified via the real Bruno CLI: 9 safe generated requests
(4 shown passing incl. stats/collections/devices; password-rules
public) execute against the server with collection-level auth.
Full-collection bru run deliberately not attempted (mutations in
static bodies would touch live data).
2026-10-24 18:58:39 -04:00

2.8 KiB

method, path, auth, area
method path auth area
GET /api/auth/users jwt+admin authentication

List Users

List all users in the system (admin only).

Endpoint: GET /api/auth/users Auth: Required (Admin only)

Query Parameters

Parameter Type Required Description
limit integer No Maximum number of users to return (default: 50)
offset integer No Number of users to skip (default: 0)
search string No Search by email or username

Request Headers

Header Type Required Description
Authorization string Yes Bearer token (must have admin role)

Example Request

GET /api/auth/users?limit=10&search=john
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response (200 OK)

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "username": "johndoe",
    "theme": "tokyo-night",
    "first_name": "John",
    "last_name": "Doe",
    "role": "user",
    "max_devices": 10,
    "created_at": "2026-02-08T10:00:00Z",
    "updated_at": "2026-02-08T10:00:00Z",
    "device_count": 3
  }
]

Response is a bare JSON array of sqlc ListUsersRows (user fields plus a device_count join) — no pagination wrapper. Live-smoke-verified 2026-10-24: password_hash is NOT in the response (an earlier draft of this doc wrongly claimed a hash leak).

Response Fields

Field Type Description
id string User ID (UUID)
email string Email address
username string Username
first_name string First name (optional)
last_name string Last name (optional)
role string User role ("user" or "admin")
theme string Theme preference (optional)
max_devices integer Maximum number of devices allowed
device_count integer Current number of registered devices
created_at string Account creation timestamp (ISO 8601)
updated_at string Last update timestamp (ISO 8601)

Error Responses

Code Description
401 Invalid or expired token
403 User does not have admin privileges