Chroma-native Auth

Chroma offers built in authentication and authorization mechanisms to secure your Chroma instance.

Auth Disabled by Default

By default, Chroma does not require authentication. You must enable it manually. If you are deploying Chroma in a public-facing environment, it is highly recommended to enable authentication.

Auth needs the company of SSL/TLS

Authentication without encryption is insecure. If you are deploying Chroma in a public-facing environment, it is highly recommended that you add (SSL/TLS)[ssl-proxy.md].

Authentication

Chroma supports two types of authentication:

  • Basic Auth - RFC 7617 compliant pre-emptive authentication with username and password credentials in Authorization header.
  • Token Auth - Standard token-based auth with Authorization or X-Chroma-Token headers.

For each authentication method there are configurations in both client and server.

Basic Authentication

Server

Generate a password file with bcrypt hashed password:

  1. docker run --rm --entrypoint echo httpd:2 "change_this_password" | htpasswd -iBc server.htpasswd user1

Multiple users

Chroma supports multiple users in the htpasswd file. You can add multiple users by running the command multiple times WITHOUT -c flag.

Environment variables:

  1. export CHROMA_SERVER_AUTHN_CREDENTIALS_FILE="server.htpasswd"
  2. export CHROMA_SERVER_AUTHN_PROVIDER="chromadb.auth.basic_authn.BasicAuthenticationServerProvider"

Running the server:

CLIDockerDocker Compose

  1. export CHROMA_SERVER_AUTHN_CREDENTIALS_FILE="server.htpasswd"
  2. export CHROMA_SERVER_AUTHN_PROVIDER="chromadb.auth.basic_authn.BasicAuthenticationServerProvider"
  3. chroma run --path /chroma-data
  1. docker run --rm -v ./server.htpasswd:/chroma/server.htpasswd \
  2. -e CHROMA_SERVER_AUTHN_CREDENTIALS_FILE="server.htpasswd" \
  3. -e CHROMA_SERVER_AUTHN_PROVIDER="chromadb.auth.basic_authn.BasicAuthenticationServerProvider" \
  4. -p 8000:8000 \
  5. chromadb/chroma:latest

Create a docker-compose.yaml with the following content:

  1. networks:
  2. net:
  3. driver: bridge
  4. services:
  5. chromadb:
  6. image: chromadb/chroma:latest
  7. volumes:
  8. - ./chromadb:/chroma/chroma
  9. - ./server.htpasswd:/chroma/server.htpasswd
  10. environment:
  11. - IS_PERSISTENT=TRUE
  12. - PERSIST_DIRECTORY=/chroma/chroma # this is the default path, change it as needed
  13. - ANONYMIZED_TELEMETRY=${ANONYMIZED_TELEMETRY:-TRUE}
  14. - CHROMA_SERVER_AUTHN_CREDENTIALS_FILE=server.htpasswd
  15. - CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.basic_authn.BasicAuthenticationServerProvider
  16. ports:
  17. - 8000:8000
  18. networks:
  19. - net

Run the following command to start the Chroma server:

  1. docker compose -f docker-compose.yaml up -d

Is my config right?

If you have correctly configured the server you should see the following line in the server logs:

  1. Starting component BasicAuthenticationServerProvider

Client

PythonJSGoJava

  1. import chromadb
  2. from chromadb.config import Settings
  3. client = chromadb.HttpClient(
  4. settings=Settings(
  5. chroma_client_auth_provider="chromadb.auth.basic_authn.BasicAuthClientProvider",
  6. chroma_client_auth_credentials="admin:admin")
  7. )
  8. # if everything is correctly configured the below should list all collections
  9. client.list_collections()
  1. // const {ChromaClient} = require("chromadb"); // CommonJS
  2. import { ChromaClient } from "chromadb"; // ES Modules
  3. const client = new ChromaClient({
  4. url: "http://localhost:8000",
  5. auth: {
  6. provider: "basic",
  7. credentials: "admin:admin",
  8. }
  9. });
  1. package main
  2. import (
  3. "context"
  4. "log"
  5. chroma "github.com/amikos-tech/chroma-go"
  6. "github.com/amikos-tech/chroma-go/types"
  7. )
  8. func main() {
  9. client, err := chroma.NewClient(
  10. chroma.WithBasePath("http://localhost:8000"),
  11. chroma.WithAuth(types.NewBasicAuthCredentialsProvider("admin", "admin")),
  12. )
  13. if err != nil {
  14. log.Fatalf("Error creating client: %s \n", err)
  15. }
  16. _, err = client.ListCollections(context.TODO())
  17. if err != nil {
  18. log.Fatalf("Error calling ListCollections: %s \n", err)
  19. }
  20. }

The below example shows auth with just headers. A more robust authentication mechanism is being implemented.

  1. package tech.amikos;
  2. import tech.amikos.chromadb.*;
  3. import tech.amikos.chromadb.Collection;
  4. import java.util.*;
  5. public class Main {
  6. public static void main(String[] args) {
  7. try {
  8. Client client = new Client(System.getenv("http://localhost:8000"));
  9. client.setDefaultHeaders(new HashMap<>() {{
  10. put("Authorization", "Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes()));
  11. }});
  12. // your code here
  13. } catch (Exception e) {
  14. System.out.println(e);
  15. }
  16. }
  17. }

Testing with cURL

  1. curl -v http://localhost:8000/api/v1/collections -u user1:change_this_password

Token Authentication

Server

Environment variables:

  1. export CHROMA_SERVER_AUTHN_CREDENTIALS="chr0ma-t0k3n"
  2. export CHROMA_SERVER_AUTHN_PROVIDER="chromadb.auth.token_authn.TokenAuthenticationServerProvider"
  3. export CHROMA_AUTH_TOKEN_TRANSPORT_HEADER="Authorization" # or X-Chroma-Token

Auth Headers

Chroma supports two token transport headers:

  • Authorization (default) - the clients are expected to pass Authorization: Bearer <token> header
  • X-Chroma-Token - the clients are expected to pass X-Chroma-Token: <token> header

The header can be configured via CHROMA_AUTH_TOKEN_TRANSPORT_HEADER environment variable.

Running the server:

CLIDockerDocker Compose

  1. export CHROMA_SERVER_AUTHN_CREDENTIALS="chr0ma-t0k3n"
  2. export CHROMA_SERVER_AUTHN_PROVIDER="chromadb.auth.token_authn.TokenAuthenticationServerProvider"
  3. export CHROMA_AUTH_TOKEN_TRANSPORT_HEADER="Authorization"
  4. chroma run --path /chroma-data
  1. docker run --rm -e CHROMA_SERVER_AUTHN_CREDENTIALS="chr0ma-t0k3n" \
  2. -e CHROMA_SERVER_AUTHN_PROVIDER="chromadb.auth.token_authn.TokenAuthenticationServerProvider" \
  3. -e CHROMA_AUTH_TOKEN_TRANSPORT_HEADER="Authorization" \
  4. -p 8000:8000 \
  5. chromadb/chroma:latest

Create a docker-compose.yaml with the following content:

  1. networks:
  2. net:
  3. driver: bridge
  4. services:
  5. chromadb:
  6. image: chromadb/chroma:latest
  7. volumes:
  8. - ./chromadb:/chroma/chroma
  9. - ./server.htpasswd:/chroma/server.htpasswd
  10. environment:
  11. - IS_PERSISTENT=TRUE
  12. - PERSIST_DIRECTORY=/chroma/chroma # this is the default path, change it as needed
  13. - ANONYMIZED_TELEMETRY=${ANONYMIZED_TELEMETRY:-TRUE}
  14. - CHROMA_SERVER_AUTHN_CREDENTIALS="chr0ma-t0k3n"
  15. - CHROMA_AUTH_TOKEN_TRANSPORT_HEADER="Authorization"
  16. - CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.token_authn.TokenAuthenticationServerProvider
  17. ports:
  18. - 8000:8000
  19. networks:
  20. - net

Run the following command to start the Chroma server:

  1. docker compose -f docker-compose.yaml up -d

Is my config right?

If you have correctly configured the server you should see the following line in the server logs:

  1. Starting component TokenAuthenticationServerProvider

Client

PythonJSGoJava

  1. import chromadb
  2. from chromadb.config import Settings
  3. client = chromadb.HttpClient(
  4. settings=Settings(
  5. chroma_client_auth_provider="chromadb.auth.token_authn.TokenAuthClientProvider",
  6. chroma_client_auth_credentials="chr0ma-t0k3n",
  7. chroma_client_auth_token_transport_header="Authorization"
  8. )
  9. )
  10. # if everything is correctly configured the below should list all collections
  11. client.list_collections()
  1. // const {ChromaClient} = require("chromadb"); // CommonJS
  2. import { ChromaClient } from "chromadb"; // ES Modules
  3. const client = new ChromaClient({
  4. url: "http://localhost:8000",
  5. auth: {
  6. provider: "token",
  7. credentials: "chr0ma-t0k3n",
  8. }
  9. });
  1. package main
  2. import (
  3. "context"
  4. "log"
  5. chroma "github.com/amikos-tech/chroma-go"
  6. "github.com/amikos-tech/chroma-go/types"
  7. )
  8. func main() {
  9. client, err := chroma.NewClient(
  10. chroma.WithBasePath("http://localhost:8000"),
  11. chroma.WithAuth(types.NewTokenAuthCredentialsProvider("chr0ma-t0k3n", types.AuthorizationTokenHeader)),
  12. )
  13. if err != nil {
  14. log.Fatalf("Error creating client: %s \n", err)
  15. }
  16. _, err = client.ListCollections(context.TODO())
  17. if err != nil {
  18. log.Fatalf("Error calling ListCollections: %s \n", err)
  19. }
  20. }

The example below shows authorization with just headers. A more robust auth mechanism is under implementation.

  1. package tech.amikos;
  2. import tech.amikos.chromadb.*;
  3. import tech.amikos.chromadb.Collection;
  4. import java.util.*;
  5. public class Main {
  6. public static void main(String[] args) {
  7. try {
  8. Client client = new Client(System.getenv("http://localhost:8000"));
  9. client.setDefaultHeaders(new HashMap<>() {{
  10. put("Authorization", "Bearer chr0ma-t0k3n");
  11. }});
  12. // your code here
  13. } catch (Exception e) {
  14. System.out.println(e);
  15. }
  16. }
  17. }

Testing with cURL

  1. curl -v http://localhost:8000/api/v1/collections -H "Authorization: Bearer chr0ma-t0k3n"

Authorization

Coming soon!

September 6, 2024