Skip to content

Commit

Permalink
Merge pull request #186 from lucagobbi/refactor_user_management
Browse files Browse the repository at this point in the history
Refactor user management
  • Loading branch information
pieroit authored Sep 12, 2024
2 parents 5113d46 + 42e5749 commit da7129a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 49 deletions.
10 changes: 5 additions & 5 deletions mkdocs/production/auth/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ However, if you want to secure your communication with the Cat as well you can d

## Securing HTTP

To enable authentication for HTTP endpoints you need to set the `CCAT_API_KEY` environment variable. This will lock the Cat HTTP endpoints and you will need to pass the value of the `CCAT_API_KEY` to authenticate your request.
To secure HTTP endpoints, set the `CCAT_API_KEY` environment variable. This will restrict access to the Cat's HTTP endpoints, requiring the value of `CCAT_API_KEY` to authenticate requests.

Enabling the API key will also enable JWT authentication. For more details [JWT Authentication](#jwt-authentication).
Enabling the API key also activates JWT authentication. For more information, see [JWT Authentication](#jwt-authentication).

## Securing WS

To enable authentication for WebSocket communication you need to set the `CCAT_API_KEY_WS` environment variable. This will lock the Cat WebSocket endpoint used for conversations. You'll need to pass the value of the `CCAT_API_KEY_WS` to ensure the Cat will open the connection.
To secure WebSocket communication, set the `CCAT_API_KEY_WS` environment variable. This will lock down the Cat’s WebSocket endpoints used for conversations. You'll need to provide the `CCAT_API_KEY_WS` value to establish a connection.

Enabling the API key will also enable JWT authentication. If you are communicating via browser, you'll probably don't want to use an API key directly in the connection URL, indeed you'll want to use a [temporary token](#jwt-authentication).
Activating the API key also enables JWT authentication. If you're communicating via a browser, it’s recommended to use a [temporary token](#jwt-authentication) instead of including the API key directly in the connection URL.

## JWT Authentication

Once you've enabled the Cat API keys variable you can also use JSON Web Token to authenticate both HTTP and WebSocket requests. To generate a valid token you can make an HTTP POST request to `/auth/token` passing username and password in the payload.
Once the Cat API key variables are enabled, you can also use JSON Web Tokens (JWT) to authenticate both HTTP and WebSocket requests. To generate a valid token, make an HTTP POST request to `/auth/token`, including your username and password in the payload.

```python

Expand Down
1 change: 1 addition & 0 deletions mkdocs/production/auth/custom-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO:Custom AuthHandler Docs
122 changes: 78 additions & 44 deletions mkdocs/production/auth/user-management.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,78 @@
# 👥 User System

The Cat provides a basic user management system that allows having separated memories for each user.
The user system affects only the [working memory](../../framework/cat-components/memory/working_memory.md) and
the [episodic memory](../../framework/cat-components/memory/long_term_memory.md).
The other memories are shared among users.

More in details, the websocket client indicates the current `user_id` by calling the `ws://localhost:1865/ws/{user_id}` endpoint.
The Cat uses such `user_id` to retrieve the user's working memory and to store the user's conversation (using the `user_id` as a metadatum).

!!! Note
Please, note that the user management system works only when using a custom client.
Its usage is not intended from the **admin** interface,
which, by default, uses `user_id = "user"`.

## Example

The Cheshire Cat provides two API clients, written in [Python](https://pypi.org/project/cheshire-cat-api/)
and [Typescript](https://www.npmjs.com/package/ccat-api), that allow exploiting the user management system.

!!! example
**Setting the `user_id` from a custom client:**
=== "Python"
```python
import cheshire_cat_api as ccat

cat_client = ccat.CatClient()
# Send a message specifying the user_id
message = "Hello my friend!!"
cat_client.send(message, user_id="user05")
```
=== "Typescript"
```typescript
import { CatClient } from 'ccat-api'

const cat = new CatClient({
baseUrl: 'localhost'
})
cat.send('Hello my friend!!', 'user05');
```

TODO: Add hook example to retrive document only few users.
# User Management

If you are developing an application that supports multiple users, it's crucial to ensure that each user's session and memories are isolated. By separating user sessions, you can prevent the mixing of user data, which is particularly important for maintaining data privacy and providing a personalized experience for each user.
[Why is this important?](#why-is-this-important)

## Shadow Users

By default, the Cat requires a unique user identifier to associate sessions and memory data with individual users.
The easiest way to provide this identifier is passing the `user_id` to HTTP endpoints or to the WebSocket messaging interface.

You can pass the user ID in the WebSocket endpoint like this:
`ws://localhost:1865/ws/{user_id}`

For HTTP endpoints, just include the `user_id` in the request header.

!!! note
If no user id is provided, the Cat will assume `user_id = "user"`.

## Internal Users

The Cat framework includes a simple, internal user management system for creating, retrieving, updating, and deleting users. This system provides a convenient, built-in way to manage JWT authentication. By default, authentication is disabled in The Cat. [Need help enabling it?](./authentication.md).

!!! note
When authenticating requests with a JWT token, you do not need to pass the `user_id`; The Cat will automatically extract it from the token.

### Managing Internal Users

#### Admin Panel

If you're looking for a straightforward way to manage users, you can use the Admin panel. Simply click on the `Settings` tab and you'll see a `User Management` section.

#### Restful API

The internal user management system is also accessible via a comprehensive RESTful API. There are endpoints for creation, retrieval, updating, and deletion of users. For more information, check the [endpoints](../../production/endpoints.md) page.

## Want to bring in your own users?

If you already have a user management system or identity provider, you can easily integrate it with the Cat by implementing a custom `AuthHandler`.

This allows you to use your own authentication logic and pass the necessary `AuthUserInfo` to the Cat. For more details, refer to the [custom auth guide](./custom-auth.md).

## Why is this important?

As stated above, when working with multiple users, it’s important to separate their sessions and memories. Without that, you'll face WebSocket connection issues and poor user experience can arise. The Cat internally use the provided `user_id` to build a WebSocket connection and tie it to a [StrayCat](../../framework/cat-components/cheshire_cat/stray_cat.md) instance which will handle the user session and memory retrieval.

### Users and memories

In the Cat, users and memories are closely related. Without user-specific memory isolation, The Cat cannot maintain context across conversations.
By default, the user system affects only the [working memory](../../framework/cat-components/memory/working_memory.md) and
the [episodic memory](../../framework/cat-components/memory/long_term_memory.md). The other memories are shared among users, but you could easily think about a custom plugin to store and restrict access to data in [Long Term Memory](../../framework/cat-components/memory/long_term_memory.md) based on `user_id`.

Here's an example of how the `user_id` could be used to filter declarative memories both on the uploading and retrieval side:

```python

from cat.mad_hatter.decorators import hook

@hook
def before_rabbithole_insert_memory(doc, cat):
# insert the user id metadata
doc.metadata["author"] = cat.user_id
return doc

@hook
def before_cat_recalls_declarative_memories(declarative_recall_config, cat):
# filter memories using the user_id as metadata.
declarative_recall_config["metadata"] = {"author": cat.user_id}
return declarative_recall_config

```

### Users and conversations

The WebSocket client and the HTTP message endpoint identifies the current `user_id` using respectively the `ws://localhost:1865/ws/{user_id}` path variable or the `user_id` in the request header.
The Cat uses this `user_id` to access the user's working memory and store conversations, using the `user_id` as metadata for retrieval.

This ensures that conversations remain isolated, preventing any mix-up between different users and providing a seamless, personalized experience.

0 comments on commit da7129a

Please sign in to comment.