Short answer: Engram project API keys open the project boundary; your application session still must derive user scopes safely—and fail closed on 401.
API design tells clients how to speak to memory; authentication decides whether that speech is trusted. A leaked key is a standing invitation to read and rewrite identity. Engram keys are bearer credentials scoped to a project; the console shows name, prefix, and created time. Application auth and memory scopes still fit together: the bearer opens the project, session logic chooses user_id and properties. This chapter covers rotation and revocation without breaking memory (dual-key windows), loading secrets from environment or vaults without logging them, and self-hosted Weaviate roles with anonymous access disabled. Revocation must be tested—agents should fail closed with 401 handling, not empty-memory fallbacks that invent preferences. Standing admin keys on interactive agents are an incident waiting for prompt injection.
API design tells clients how to speak to memory. Authentication decides whether that speech is trusted. Memory systems hold preferences, procedures, and private history. A leaked key is not a brief inconvenience. It is a standing invitation to read and rewrite identity. This chapter covers how Weaviate Engram authenticates with project-scoped API keys, how application identity must still derive user scopes safely, how to store and rotate secrets, and how self-hosted Weaviate layers API keys with roles when you operate the database yourself.
What Does an Engram API Key Actually Authorize?
Engram keys are bearer credentials. Every REST call sends Authorization: Bearer with the key. The Python client takes the same secret at construction time. Keys are scoped to a project. All memories created with that key live inside that project boundary. The console shows name, prefix, created time, and last used. The full secret appears only once at creation. Copy it into a vault immediately.
That project scope is strong isolation between products. It is not end-user authentication. The key proves your backend may talk to Engram. It does not prove which human is chatting. user_id and property scopes still come from your application. If you accept those fields verbatim from an untrusted client, a valid service key can be abused to query another person’s memories.
Treat the Engram key like a database password for a memory partition. Put it only on trusted servers, workers, and carefully brokered agent runtimes. Do not ship it inside mobile apps, browser bundles, or public agent prompts.
How Should Application Auth and Memory Scopes Fit Together?
Build a clear handoff. Your edge authenticates the human or workload with sessions, OIDC, or mutual TLS. Your service then maps that principal to Engram user_id and properties. Never let the model or the browser invent the scope map. Server-side derivation is the security boundary. Defense in depth still checks that search results match the expected user before they enter a prompt.
Issue separate Engram keys per workload when you can. A read-heavy support agent, a write-heavy ingestion worker, and a break-glass admin job should not share one immortal secret. Name keys after the workload so last-used timestamps and deletions are meaningful. On Weaviate Cloud database clusters, RBAC roles such as viewer versus admin refine what a key may do. Engram project keys already confine you to that project’s memory graph.
Agents amplify key risk. They call APIs often, log liberally, and sometimes echo configuration. Keep secrets out of tool results and trace payloads. Prefer a credential broker or secret manager that injects the key at runtime over baking it into images.
How Do You Rotate and Revoke Without Breaking Memory?
Plan rotation as a dual-key window. Create a new Engram key, deploy it to services, confirm traffic and last-used on the new prefix, then delete the old key. Do not rotate by editing a string in five repos by hand on incident day. Automate distribution from a vault. Event-driven rotation after a leak beats calendar rotation alone, but calendar rotation still limits the lifetime of unnoticed exposure.
Self-hosted Weaviate adds database user keys you can create and rotate through the user management API without restarting the cluster. Assign roles with least privilege. Disable anonymous access in every non-local environment. Static keys in environment files work for demos. Production should prefer managed users and secret stores so rotation does not require a redeploy of plaintext compose files.
Revocation must be tested. Delete a key in staging and confirm agents fail closed with 401 handling, not with empty-memory fallbacks that invent preferences. Empty recall on auth failure is a product bug dressed as resilience.
How Should Code Load Secrets When Calling Weaviate Engram?
Read keys from the environment or a secret sidecar at process start. Construct one client per process. Avoid logging the key, the bearer header, or truncated middle sections that still leak enough entropy. Redact authorization headers in HTTP dumps. For local plugins that need Engram, keep keys in shell profiles or OS keychains, not in committed config.
Here is a stained glass atelier service that loads the Engram key from the environment, binds bay scope from an authenticated staff principal, and refuses client-supplied user overrides.
import os
from engram import EngramClient, HybridRetrieval
# Secret stays in the environment / vault injection — never in source
api_key = os.environ["ENGRAM_API_KEY"]
client = EngramClient(api_key=api_key)
group = "stained_glass_atelier"
def principal_from_session(session: dict) -> dict:
"""Map verified app auth to Engram scopes. Ignore client-provided user_id."""
if not session.get("verified"):
raise PermissionError("unauthenticated")
return {
"user_id": session["staff_id"], # e.g. glazier-rosa
"properties": {
"bay_id": session["bay_id"], # e.g. glass-bay-north
"cost_center": "studio",
},
}
def remember_for_session(session: dict, user_text: str, assistant_text: str) -> str:
scopes = principal_from_session(session)
run = client.memories.add(
[
{"role": "user", "content": user_text},
{"role": "assistant", "content": assistant_text},
],
user_id=scopes["user_id"],
group=group,
properties=scopes["properties"],
)
return run.run_id
def recall_for_session(session: dict, question: str) -> list[str]:
scopes = principal_from_session(session)
hits = client.memories.search(
query=question,
user_id=scopes["user_id"],
group=group,
properties=scopes["properties"],
retrieval_config=HybridRetrieval(limit=4),
)
# Defense in depth: only return memories for the session user
return [m.content for m in hits if getattr(m, "user_id", scopes["user_id"]) in (None, scopes["user_id"])]
session = {
"verified": True,
"staff_id": "glazier-rosa",
"bay_id": "glass-bay-north",
}
run_id = remember_for_session(
session,
"Bay north: keep the cobalt pot at 1180C and anneal face panels for twelve hours before leading.",
"Logged cobalt pot temperature and anneal duration for bay north.",
)
print({"run_id": run_id, "memories": recall_for_session(session, "What anneal rule applies in bay north?")})
If ENGRAM_API_KEY is missing, fail at startup. A half-configured memory client that silently skips auth checks will ship.
Which Operational Checks Keep Key Hygiene Honest?
Inventory keys by workload and environment. Alert on unexpected last-used spikes. Scrub CI logs for eng_ prefixes. Ban keys from tickets and chat. After staff changes, delete keys they could have copied. Pair key deletion with the environment separation habits in the next chapter so staging credentials never open production memory.
For underlying Weaviate clusters, review RBAC assignments when services change shape. A migration worker may need broader rights for a week. Revert them when the cutover ends. Standing admin keys on interactive agents are an incident waiting for a prompt injection.
Authentication for memory is project keys plus application identity. Engram bearers open the project. Your session logic chooses the user and properties. Store secrets in vaults, rotate with dual-key windows, and fail closed on 401. Separate environments then keep those carefully managed keys from crossing the wrong blast radius.
Our next chapter, How do you separate staging and production memory stores?, shows how to isolate staging and production Engram projects and keys so tests never contaminate live agent memory.