> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cyborg.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage Users (RBAC)

CyborgDB supports role-based access control (RBAC) through per-user keys. The holder of the
**root** index KEK can mint per-user wrapped keys that grant read and/or write access to an index.

## How RBAC works

* **Per-index KEK.** Each index is encrypted under a 32-byte Key-Encryption-Key (KEK), the
  `index_key`. CyborgDB wraps a data key (DEK) under the KEK internally — callers only ever handle
  the KEK.
* **Per-user keys.** The root KEK holder calls `CreateUserKeys` to wrap the index key under a
  per-user 32-byte key (`user_kek`), granting read and/or write access. **The set of wraps that
  exist defines the permission set** — there is no separate permission flag. A read-only user
  simply has no write wrap.
* **Root-gated administration.** Creating, deleting, and listing user keys always requires the
  root index KEK.
* **User load.** A user then opens the index with their own `user_kek`, scoped to their `user_id`:
  ```cpp theme={null}
  auto index = client.LoadIndex(index_name, user_kek, /*logger=*/nullptr, user_id);
  ```
  Per-operation, the gate is enforced — a read-only user's `Upsert`/`Delete` are rejected.

<Note>Pass a per-user key context to data operations as `cyborg::KeyContext{user_kek, user_id}`
where `user_id` is a `std::array<uint8_t, 16>` and `user_kek` is a `std::array<uint8_t, 32>`.</Note>

***

## CreateUserKeys

```cpp theme={null}
void CreateUserKeys(const std::array<uint8_t, 16>& user_id,
                    const std::array<uint8_t, 32>& index_key,
                    const std::array<uint8_t, 32>& user_kek,
                    bool grant_read,
                    bool grant_write);
```

Mints per-user wrapped keys granting the requested permissions.

### Parameters

| Parameter     | Type                      | Description                                           |
| ------------- | ------------------------- | ----------------------------------------------------- |
| `user_id`     | `std::array<uint8_t, 16>` | 16-byte user identifier.                              |
| `index_key`   | `std::array<uint8_t, 32>` | The **root** index KEK (admin gate).                  |
| `user_kek`    | `std::array<uint8_t, 32>` | The user's 32-byte key under which access is wrapped. |
| `grant_read`  | `bool`                    | Grant read access.                                    |
| `grant_write` | `bool`                    | Grant write access.                                   |

<Warning>At least one of `grant_read` / `grant_write` must be `true`.</Warning>

### Exceptions

<AccordionGroup>
  <Accordion title="std::runtime_error">
    * Throws if the supplied key is not the root index KEK.
    * Throws if the user keys could not be created.
  </Accordion>
</AccordionGroup>

***

## DeleteUserKeys

```cpp theme={null}
void DeleteUserKeys(const std::array<uint8_t, 16>& user_id,
                    const std::array<uint8_t, 32>& index_key);
```

Revokes a user's access by deleting their wrapped keys. Idempotent and root-gated.

### Parameters

| Parameter   | Type                      | Description                          |
| ----------- | ------------------------- | ------------------------------------ |
| `user_id`   | `std::array<uint8_t, 16>` | 16-byte user identifier to revoke.   |
| `index_key` | `std::array<uint8_t, 32>` | The **root** index KEK (admin gate). |

### Exceptions

<AccordionGroup>
  <Accordion title="std::runtime_error">
    * Throws if the supplied key is not the root index KEK.
  </Accordion>
</AccordionGroup>

***

## ListUserKeys

```cpp theme={null}
std::vector<UserKeyInfo> ListUserKeys(const std::array<uint8_t, 32>& index_key);
```

Lists all users that have keys for the index and their permissions. Root-gated.

### Parameters

| Parameter   | Type                      | Description                          |
| ----------- | ------------------------- | ------------------------------------ |
| `index_key` | `std::array<uint8_t, 32>` | The **root** index KEK (admin gate). |

### Returns

`std::vector<UserKeyInfo>`: One entry per user. The `UserKeyInfo` struct:

```cpp theme={null}
struct UserKeyInfo {
    std::array<uint8_t, 16> user_id;
    bool has_read;
    bool has_write;
};
```

### Exceptions

<AccordionGroup>
  <Accordion title="std::runtime_error">
    * Throws if the supplied key is not the root index KEK.
  </Accordion>
</AccordionGroup>

***

## Example Usage

```cpp theme={null}
#include "cyborgdb_core/client.hpp"
#include "cyborgdb_core/encrypted_index.hpp"
#include <openssl/rand.h>
#include <array>

// ... Initialize the client and load/create the index with the root index_key ...

// 16-byte user identifier and the user's 32-byte key (16/32 random bytes each)
std::array<uint8_t, 16> user_id;
std::array<uint8_t, 32> user_kek;
RAND_bytes(user_id.data(), user_id.size());
RAND_bytes(user_kek.data(), user_kek.size());

// Admin (root KEK holder) grants the user read-only access
index->CreateUserKeys(user_id, index_key, user_kek, /*grant_read=*/true, /*grant_write=*/false);

// Inspect current users
for (const auto& info : index->ListUserKeys(index_key)) {
    std::cout << "read=" << info.has_read << " write=" << info.has_write << "\n";
}

// The user loads the index scoped to their identity
auto user_index = client.LoadIndex("my_index", user_kek, /*logger=*/nullptr, user_id);

// Per-operation, the user passes a per-user key context
cyborg::Array2D<float> q{{0.1f, 0.2f, 0.3f, 0.4f}};
auto results = user_index->Query(q, cyborg::QueryParams{}, cyborg::KeyContext{user_kek, user_id});

// Revoke access when done
index->DeleteUserKeys(user_id, index_key);
```
