Most vector database projects start with one developer, one environment, and one API key. That works fine until it does not. A second developer joins and you paste them the key over Slack. A staging environment gets stood up and uses the same credentials as production. Someone leaves the team and you wonder how long it will take to rotate the key without breaking the three services that depend on it.
None of this is unique to vector databases — credential sprawl is a universal problem. But vector databases sit close to your data and your AI pipelines, which means a leaked or unrevoked key can expose embeddings, indexes, and the content behind your retrieval system. Getting the key management right early is cheaper than cleaning it up after something goes wrong.
This article covers how to think about API key safety across environments and teams, then shows how Weaviate’s tooling maps to each concern.
The Core Problem with Shared Keys
When one key does everything, every incident becomes a worst-case incident. A key that has read access, write access, and admin access — shared across dev, staging, and production — means that if any one of those environments leaks credentials, an attacker has full access to all of them.
The blast radius problem is also organizational. When a contractor finishes their work, or a teammate moves to a different project, rotating the single shared key means updating every service and environment that uses it simultaneously. Teams avoid doing this because of the coordination cost, so the key never actually gets rotated.
The solution is not more complex tooling. It is just using a separate credential for each context that needs one.
Keep Secrets Out of Source Code
Before anything else: credentials should never appear in source code, committed files, or notebooks. This includes .env files that get accidentally committed, hardcoded strings in connection setup, and API keys embedded in Jupyter notebooks that get shared or exported.
The standard approach is environment variables. The key lives in the environment, not in the code. The code reads it at runtime.
export WEAVIATE_URL="https://your-cluster-url"
export WEAVIATE_API_KEY="your-api-key"
Then in your application:
import os
weaviate_url = os.getenv("WEAVIATE_URL")
weaviate_key = os.getenv("WEAVIATE_API_KEY")
This pattern works whether you are running locally, in a CI pipeline, or on a server. Each environment sets its own variables with its own values — the code stays identical across all of them.
For Kubernetes deployments, the same principle applies at a different layer. Store API keys in Kubernetes Secrets rather than in plaintext values.yaml files or config maps. A secret that lives in version-controlled YAML is not actually a secret.
One Key Per User or Service
Once credentials are out of source code, the next improvement is scoping them. Instead of one key shared across all teammates and services, each actor gets its own key. This solves the rotation problem: when access needs to be revoked, you revoke one key, not all of them.
It also creates an audit trail. If something unusual happens — unexpected writes, high query volume, access from an unfamiliar IP — you can trace it to a specific key and therefore a specific user or service rather than trying to figure out which of eight consumers was responsible.
Managing Keys in Weaviate
Weaviate v1.30 introduced a database user management API that handles this directly. You can create individual keys for teammates and services without restarting the cluster.
# Create a dedicated user — returns a unique API key for that user
user_api_key = client.users.db.create(user_id="search-service")
The user_id is a label you choose. Make it descriptive — something that identifies the service or person the key belongs to. search-service, data-ingestion-pipeline, alice, staging-reader are all reasonable choices. Vague names like key1 make auditing harder.
Once the user exists, assign them only the roles they actually need:
client.users.db.assign_roles(
user_id="search-service",
role_names=["searchApplication"]
)
A service that only queries data should only have read access. A service that ingests documents needs write access to specific collections. The admin key — which can create indexes, delete data, and manage other users — should belong to as few things as possible and should never be the key your application uses in production.
This combination of per-user keys and role-based access control (RBAC) means that a compromised search-service key can read data but cannot delete an index, cannot read from collections it was not granted access to, and cannot create new users with elevated permissions.
Rotating Keys Without Downtime
Key rotation is where shared-key setups become painful. If everything uses the same key and you need to rotate it, you have to update every service simultaneously or accept a period where some services use the old key and some use the new one.
Per-user keys solve this. You rotate one user’s key and update one service.
new_api_key = client.users.db.rotate_key(user_id="search-service")
This generates a new key for that user and invalidates the old one. The teammate who left, the service that was decommissioned, the key that may have been exposed — any of these can be handled independently without touching anything else.
For Weaviate Cloud deployments, key rotation is also available directly in the console under Cluster details → API Keys, which is useful when you need to act quickly and do not want to write code to do it.
Handling Large Teams with OIDC
For larger organizations with many teammates spread across teams, managing individual database users eventually hits its own limits. Creating a Weaviate user for every person in the company, keeping those users in sync with your HR system, and handling onboarding and offboarding across departments is its own operational burden.
The enterprise answer to this is integrating with an OIDC identity provider — Okta, Azure AD, Auth0, and similar platforms. Instead of Weaviate managing credentials directly, it delegates authentication to your organization’s existing identity infrastructure. Weaviate validates short-lived tokens issued by the IdP and never stores passwords itself.
This approach means that when someone joins or leaves the company, their access to every system — including Weaviate — is controlled centrally. No separate offboarding step for the vector database.
A Summary of the Practices
| Practice | What it solves |
|---|---|
| Environment variables | Keeps secrets out of source code and version control |
| One key per user or service | Limits blast radius if a key leaks; enables targeted revocation |
| Least-privilege roles | Reduces what a compromised key can actually do |
| Rotate on offboarding | Ensures revoked access is truly revoked, not just ignored |
| OIDC for large teams | Centralizes identity management across the whole organization |
None of these practices require exotic tooling. The main thing they require is doing them before a problem forces you to. Setting up per-user keys and environment variable discipline on day two of a project takes an hour. Doing it after a key has been sitting in a shared Slack channel for six months — while also keeping production running — takes considerably longer.