Per-Agent Keypair Registration
What this page is
Agents register an Ed25519 public key with the node, then sign each fact payload. The node verifies the signature before writing โ cryptographically verifiable source provenance on asserted facts.
Keypair attestation is opt-in per assertion.
The existing Bearer-key model is unaffected. Set
STIGMEM_ATTESTATION_REQUIRED=true to make it mandatory
node-wide.
Stigmem's source field identifies who asserted a fact
(agent:settings-sync, oidc:alice@example.com, etc.), but prior to
Track C the node accepted any source value the caller provided. C1
closes this gap.
How it worksโ
Agent Stigmem node
โ โ
โ POST /v1/auth/agent-keys โ
โ { public_key, description } โโโโบ โ stores public key against entity_uri
โ โ
โ POST /v1/facts โ
โ { ...fact, attestation: { โ
โ key_id, signature } } โโโโบ โ verifies sig โ stores attested_key_id
โ โ
โ โ GET /v1/audit returns full trail:
โ โ principal โ attested key โ fact
Endpointsโ
POST /v1/auth/agent-keys ยท register a keyโ
Register an Ed25519 public key for the calling entity. Requires
write permission.
Request body:
{
"public_key": "<base64url-encoded 32-byte Ed25519 public key>",
"description": "my-coding-assistant prod keypair"
}
description is optional but recommended for audit readability.
Response (201 Created):
{
"id": "uuid",
"entity_uri": "agent:my-service",
"public_key": "base64url...",
"description": "my-coding-assistant prod keypair",
"registered_at": "2026-05-03T01:00:00Z",
"status": "active"
}
Save the id โ it is the key_id you include in every attestation token.
GET /v1/auth/agent-keys ยท list my keysโ
Returns all keys (active and revoked) registered by the calling entity.
curl -H 'Authorization: Bearer stgm_...' \
http://localhost:8000/v1/auth/agent-keys | jq .
DELETE /v1/auth/agent-keys/{key_id} ยท revoke a keyโ
Marks the key as revoked. Revoked keys are rejected at attestation
verification. Callers may only revoke their own keys.
curl -s -X DELETE \
-H 'Authorization: Bearer stgm_...' \
http://localhost:8000/v1/auth/agent-keys/<key-id>
# โ 204 No Content
Error responses:
403404409Attesting a fact assertionโ
Include an attestation object in the POST /v1/facts body:
{
"entity": "user:alice",
"relation": "memory:context",
"value": { "type": "str", "v": "working on stigmem docs" },
"source": "agent:my-service",
"confidence": 1.0,
"scope": "local",
"attestation": {
"key_id": "<uuid from registration>",
"signature": "<base64url Ed25519 signature>"
}
}
Canonical messageโ
Sign the following UTF-8 string with your private key:
{entity}\n{relation}\n{value.type}\n{encoded_v}\n{source}
strfloatrepr(float)bool"true" / "false"jsonPython example (using the cryptography library):
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import base64, json
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
# Register the public key once
pub_bytes = public_key.public_bytes_raw()
pub_b64 = base64.urlsafe_b64encode(pub_bytes).rstrip(b"=").decode()
# Per-assertion: build canonical message and sign
entity = "user:alice"
relation = "memory:context"
val_type = "str"
val_v = "working on stigmem docs"
source = "agent:my-service"
canonical = f"{entity}\n{relation}\n{val_type}\n{val_v}\n{source}".encode("utf-8")
sig_bytes = private_key.sign(canonical)
sig_b64 = base64.urlsafe_b64encode(sig_bytes).rstrip(b"=").decode()
payload = {
"entity": entity,
"relation": relation,
"value": {"type": val_type, "v": val_v},
"source": source,
"confidence": 1.0,
"scope": "local",
"attestation": {"key_id": "<registered-key-id>", "signature": sig_b64},
}
Making attestation mandatoryโ
Set STIGMEM_ATTESTATION_REQUIRED=true in the node environment. With
this flag:
Every assert needs attestation
Every POST /v1/facts must include a valid attestation object.
Unattested requests rejected
Returns 400 Bad Request: "attestation required; register an agent key at POST /v1/auth/agent-keys".
Default is false for backward compatibility with clients that
predate Track C.
Migration pathโ
attestation to each assertion.STIGMEM_ATTESTATION_REQUIRED=trueattestation field becomes required.