Flair uses cryptographic identity (Ed25519) for agent authentication. Within an org, memory reads are open — agents see each other's non-private memories — while writes are isolated per agent and private memories stay strictly owner-only. The hard access boundary is the federation edge (cross-instance).
Every request includes an Authorization header:
TPS-Ed25519 <agentId>:<timestamp>:<nonce>:<signature>
The signature covers agentId:timestamp:nonce:METHOD:/path using the
agent's Ed25519 private key. The server verifies against the agent's
registered public key.
- Replay window: 30 seconds
- Nonce deduplication: Prevents replay within the window
- No shared secrets: Each agent has its own key pair
Admin operations (agent management, backup, restore) use Harper's built-in HTTP Basic auth:
Authorization: Basic <base64(admin:password)>
The admin password is generated on flair init and stored at
~/.flair/admin-pass (mode 0600, owner-only) — it can also be set
explicitly via --admin-pass-file, FLAIR_ADMIN_PASS, or
HDB_ADMIN_PASSWORD. It is never printed to the console. See
docs/secrets-and-keys.md for the full
precedence and rotation model.
The Harper operations API is the admin/management surface. Network
requests to it require admin Basic auth: Flair ships with
authorizeLocal: false, so an unauthenticated loopback request is
rejected (401) instead of being auto-elevated to super_user. The same
API is also reachable over a Unix domain socket
(~/.flair/data/operations-server, owner-write-only), which Harper
treats as an inherent local-admin channel — a request over the socket is
authorized as super_user without credentials. This is by design (the
admin-password rotation flow relies on it) and is constrained to the box
owner; see Threats NOT Mitigated below.
Reads are open within an org; writes are isolated per agent. Enforced at
the database layer (Harper resource search() override via a single
centralized read-scope rule), not application logic:
GET /Memory/— returns the authenticated agent's own memories (any visibility) plus every non-private memory in the orgPOST /MemorySearch— same read scope: own memories plus all non-privatePOST /Memory— writes are attributed to the authenticated agent; an agent cannot write as another (write isolation)
Private memories are strictly owner-only — a memory written with
visibility: private is returned only to its author, never to another agent.
Within an org, an agent reads every non-private memory directly — no grant
required. This is deliberate: the goal is relevance (surface what's useful to
the org) over secrecy. A writer keeps something private by marking it
visibility: private, which keeps it strictly owner-only. The access boundary
that stays hard is the federation edge (cross-instance / cross-org), not
within-org reads.
Admin-authenticated requests bypass agent scoping. Admin can read all memories, all souls, and all agent records. SQL and GraphQL endpoints are restricted to admin-only.
Private keys are stored at ~/.flair/keys/<agentId>.key with 0600
permissions (owner read/write only). Legacy path ~/.tps/secrets/flair/
is supported with deprecation warnings.
Keys are generated during flair agent add using Ed25519 (via tweetnacl).
The 32-byte seed is stored; the full 64-byte secret key is derived at
runtime.
flair agent rotate-key <id> generates a new key pair, updates the
public key in Flair, and backs up the old key as <agentId>.key.bak.
- Agent impersonation: Ed25519 signatures prevent one agent from acting as another without possessing the private key.
- Private-memory leakage: memories marked
visibility: privateare strictly owner-only and never returned to another agent. Non-private memories are intentionally readable within the org (by design, not leakage); the cross-instance boundary is the federation edge. - Write forgery: writes are attributed to the authenticated agent — an agent cannot write memories as another.
- Replay attacks: 30-second window + nonce deduplication.
- Privilege escalation via SQL: SQL and GraphQL endpoints blocked for non-admin agents.
- Admin token theft from filesystem: Admin credentials are only in process environment, never on disk.
- Same-OS-user key theft: If multiple agents run as the same OS user, file permissions alone don't prevent key access. Use process-level sandboxing (nono, Docker, separate users) to isolate agents.
- Memory dumps: Private keys exist in process memory. A compromised process could extract them.
- Network sniffing: Flair uses HTTP by default. Use HTTPS in production or restrict to localhost.
- Same-OS-user ops-API socket access: the operations-API domain
socket (
operations-server, owner-write-only) is an unauthenticated super_user channel by Harper design — any process running as the box owner can perform admin operations through it (the admin-password rotation flow uses this path). Owner-write permissions keep it unreachable by other OS users, co-tenants, and the network; isolate untrusted workloads to separate OS users.
- Use HTTPS for any non-localhost deployment
- Sandbox agents with nono, Docker, or separate OS users
- Rotate keys periodically with
flair agent rotate-key - Back up with
flair backup— backup files contain memory content and should be treated as sensitive - Monitor with
flair status— warns about key permission issues