Skip to content

Identity & access

IAM is included in Lupid as one capability — not the whole product. If full IAM is the only thing you need, you can run Lupid for just that and ignore everything else. Most deployments use the runtime protection and the audit trail too, but the choice is yours.

PrincipalWhat they areHow they authenticate
AgentA non-human consumer of policy decisions (an LLM agent, a script)Ed25519 keypair + JWT session
OperatorA human using the dashboard or CLIEmail + bcrypt-hashed password (via NextAuth) and HMAC header to the API

Each agent registered with Lupid gets:

  1. An Ed25519 keypair. The private key is encrypted at rest in Postgres with AES-256-GCM (key from AGENTUM_ENCRYPTION_KEY_HEX).
  2. A signed passport. The public key plus the agent metadata, signed by the server’s signing key.
  3. A JWT session token scoped to the agent’s network context (source IP can be bound at issue time).

The agent presents the JWT on every request. Lupid’s agentum-authn crate verifies the signature, looks the token up in the revocation blocklist, and reads the agent’s declared tools to seed the policy evaluation context.

Operators log into the dashboard with email + password. The password is bcrypt-hashed server-side. The session is a NextAuth-encrypted JWT cookie sealed with NEXTAUTH_SECRET.

Every API call the dashboard makes carries an HMAC-SHA256 header (X-Agentum-Operator) signed with AGENTUM_OPERATOR_SECRET_HEX. The HMAC payload includes a 5-minute time window so a stolen header expires quickly.

On the very first start, when the operators table is empty and AGENTUM_ADMIN_EMAIL and AGENTUM_ADMIN_PASSWORD are both set in .env, Lupid creates exactly one admin operator from those values. The password is bcrypt-hashed in-process; the plaintext is never written to disk past the .env.

Subsequent boots log skipping initial-admin bootstrap and never overwrite the row. After first boot, create additional operators from the dashboard’s Settings → Users page or via agentum operator create.

Three roles, in order of increasing privilege:

RoleCan readCan write
viewereverythingnothing
operatoreverythingack / resolve alerts, decide HITL requests, kill agents
admineverythingthe above + mint API keys, register agents, edit policies, manage operator accounts (create / update / delete)

Mint an admin key for full operator capability. The HMAC bootstrap payload signs with admin for the same reason — it’s the top of the hierarchy.

Every agent has a state machine. Operators can transition with one click:

Provisioning → Active → Suspended → Quarantined → Decommissioned
  • Active. Normal operation. JWTs verify, policy evaluates, calls flow.
  • Suspended. JWT added to the revocation blocklist. The agent’s next request fails authentication. Reversible.
  • Quarantined. Suspended plus every audit event from this agent is tagged for investigator review. Use when you suspect compromise.
  • Decommissioned. Terminal state. The agent is archived; new requests are rejected with agent_not_found.

Revocation propagates via Postgres LISTEN/NOTIFY across every Lupid replica in the cluster, so the kill is effective everywhere within ~100 ms. The blocklist itself is an XOR8-style filter in memory backed by the revocation_blocklist table.