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

## createUser

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

```typescript theme={null}
async createUser({ permissions: string[] }): Promise<{ userId: string; apiKey: string }>
```

### Parameters

| Parameter | Type | Description |
| - | - | - |
| `permissions` | `string[]` | Non-empty subset of `['read', 'write']`. |

### Returns

`Promise<{ userId, apiKey }>`:

| Field | Type | Description |
| - | - | - |
| `userId` | `string` | Hex identifier for the new user. |
| `apiKey` | `string` | The user's API key, starting with `cdbk_`. |

<Warning>The service returns `apiKey` 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

```typescript theme={null}
import { Client } from 'cyborgdb';

const ROOT_KEY = 'your-service-root-key';
const indexKey = new Uint8Array(Buffer.from('your-64-character-hex-key', 'hex'));

const admin = new Client({ baseUrl: 'http://localhost:8000', apiKey: ROOT_KEY });
const index = await admin.loadIndex({ indexName: 'documents', indexKey });

const user = await index.createUser({ permissions: ['read', 'write'] });
console.log(Object.keys(user).sort());
// Output: [ 'apiKey', 'userId' ]

// The user connects with their own key
const userClient = new Client({ baseUrl: 'http://localhost:8000', apiKey: user.apiKey });
```

***

## listUsers

Lists the users created for this index.

```typescript theme={null}
async listUsers(): Promise<{ userId: string; permissions: string[] }[]>
```

### Returns

An array of `{ userId, permissions }`, where `permissions` is a subset of `['read', 'write']`.

### Example

```typescript theme={null}
await index.createUser({ permissions: ['read'] });

for (const u of await index.listUsers()) {
    console.log(u.permissions);
}
// Output: [ 'read' ]
```

<Note>Deleting an index doesn't delete its user records. If you create a new index with the same name, `listUsers()` 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 `deleteUser()`.</Note>

***

## deleteUser

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

```typescript theme={null}
async deleteUser({ userId: string }): Promise<void>
```

### Parameters

| Parameter | Type | Description |
| - | - | - |
| `userId` | `string` | `userId` from `createUser()` or `listUsers()`. |

### Example

```typescript theme={null}
const { userId } = await index.createUser({ permissions: ['read'] });
await index.deleteUser({ userId });

console.log(await index.listUsers());
// Output: []
```

***

## Exceptions

These apply to all three methods:

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

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

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

  <Accordion title="CyborgDBServiceError">
    The service returns `5xx`.
  </Accordion>
</AccordionGroup>

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


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