> ## 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.

# User Management (RBAC)

When the service runs with `CYBORGDB_SERVICE_ROOT_KEY` set, `EncryptedIndex` can create, list, and revoke per-index users. These methods require a client created with the root key.

<Note>See [Multi-Tenancy & RBAC](../../guides/advanced/multi-tenancy) for the operator-side playbook (modes, key kinds, SDK-supplied indexes).</Note>

## create\_user

Creates a user scoped to this index and returns their API key.

```python theme={null}
index.create_user(permissions: List[str]) -> Dict[str, str]
```

### Parameters

| Parameter | Type | Description |
| - | - | - |
| `permissions` | `List[str]` | Non-empty subset of `["read", "write"]`. |

### Returns

`Dict[str, str]`:

| Key | Type | Description |
| - | - | - |
| `user_id` | `str` | Hex identifier for the new user. |
| `api_key` | `str` | The user's API key, starting with `cdbk_`. |

<Warning>The service returns `api_key` only in this response and never stores it. Give it to the user over a secure channel and don't log it. If it's lost, delete the user and create a new one.</Warning>

### Example

```python theme={null}
from cyborgdb import Client

ROOT_KEY = 'your-service-root-key'
index_key = bytes.fromhex('your-64-character-hex-key')

admin = Client(base_url='http://localhost:8000', api_key=ROOT_KEY)
index = admin.load_index('documents', index_key)

user = index.create_user(permissions=['read', 'write'])
print(sorted(user.keys()))
# Output: ['api_key', 'user_id']

# The user connects with their own key
user_client = Client(base_url='http://localhost:8000', api_key=user['api_key'])
```

***

## list\_users

Lists the users created for this index.

```python theme={null}
index.list_users() -> List[Dict[str, Any]]
```

### Returns

A list of dicts:

| Key | Type | Description |
| - | - | - |
| `user_id` | `str` | Hex identifier. |
| `permissions` | `List[str]` | Subset of `["read", "write"]`. |

### Example

```python theme={null}
for u in index.list_users():
    print(u['user_id'], u['permissions'])
# Output: 99a4a548e6824c45c84ca7c64535fcc9 ['read', 'write']
```

<Note>Deleting an index doesn't delete its user records. If you create a new index with the same name, `list_users()` on it still returns the old users. They can't read the new index, because their keys don't unwrap its data key; delete them with `delete_user()`.</Note>

***

## delete\_user

Revokes a user. Their access keys for this index are erased, so their `cdbk_` key stops working on the next request.

```python theme={null}
index.delete_user(user_id: str) -> None
```

### Parameters

| Parameter | Type | Description |
| - | - | - |
| `user_id` | `str` | `user_id` from `create_user()` or `list_users()`. Deleting an ID that doesn't exist succeeds without an error. |

### Example

```python theme={null}
index.delete_user(user['user_id'])
print(index.list_users())
# Output: []
```

***

## Exceptions

These apply to all three methods:

<AccordionGroup>
  <Accordion title="cyborgdb.AuthenticationError">
    The client isn't using the root key (HTTP `403`), or its `api_key` is invalid (HTTP `401`).
  </Accordion>

  <Accordion title="cyborgdb.ValidationError">
    `permissions` is empty or contains a value other than `"read"` or `"write"`, or `user_id` isn't hex (HTTP `400`).
  </Accordion>

  <Accordion title="cyborgdb.NotFoundError">
    The index doesn't exist (HTTP `404`).
  </Accordion>

  <Accordion title="cyborgdb.ServiceError / cyborgdb.TransportError">
    The service returns `5xx` or can't be reached.
  </Accordion>
</AccordionGroup>

See [Errors](../errors) for the full hierarchy.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.