GoodMemGoodMem
How-To GuidesUsers and Access

Issue Scoped API Keys

Create API keys with immutable permission ceilings for agents, CI jobs, and integrations that should not hold your full authority.

Issue Scoped API Keys

By default, an API key inherits the live authority of the principal it authenticates as. Whatever you can do, the key can do, including things you are granted permission to do next month. That is convenient for your own laptop and a poor deal for an agent, a CI job, or a vendor integration that only needs to search one space.

A scoped key carries a ceiling: a list of rules fixed at issuance that the key can never exceed. Every request through a scoped key must pass two independent checks — the subject's live authority at request time, and the ceiling. If the key leaks, the damage is bounded by the ceiling regardless of what its subject is allowed to do. The concepts behind this are covered in API Keys and Ceilings.

This guide issues two scoped keys against a real space and shows what the server does when you ask for a ceiling you are not entitled to grant.

Before You Start

  • GoodMem server running, goodmem CLI installed and authenticated.
  • A space with at least one memory in it. Capture its UUID:
export SPACE_ID="$(goodmem space list --format json | jq -r '.spaces[0].spaceId')"

1. The Ceiling Rule Grammar

A ceiling rule names one operation and one selector, colon-delimited:

OPERATION:SELECTOR[:RESOURCE_KIND:RESOURCE_UUID]
  • ANY and OWN selectors take no resource segments: LIST_SPACE:ANY.
  • EXACT and DIRECT_MEMBERS_OF require a resource kind and UUID: READ_SPACE:EXACT:SPACE:1cf3.... The one exception is INSTANCE, which is a singleton and takes no UUID.
  • Tokens accept upper or lower case and hyphens or underscores; direct-members-of and DIRECT_MEMBERS_OF parse the same way.

The full operation catalog is in the Operations and Selectors reference. --ceiling is repeatable, and --authority-mode scoped requires at least one rule.

2. Issue a Retrieval-Only Key

Retrieval over a space checks two gates: LIST_MEMORY on the space itself, and READ_MEMORY on the memories the space directly contains. A ceiling that includes one without the other produces a key that fails every retrieval, so include both:

goodmem apikey create \
  --authority-mode scoped \
  --ceiling LIST_MEMORY:EXACT:SPACE:$SPACE_ID \
  --ceiling READ_MEMORY:DIRECT_MEMBERS_OF:SPACE:$SPACE_ID \
  --label purpose=support-bot

The raw key (gm_...) appears once, in this response. The server stores only a verifier and cannot show the key again.

The DIRECT_MEMBERS_OF rule covers every memory the space contains now or later, and nothing else — not the space's configuration, not a sibling space, not the embedders the space references.

No EXECUTE_EMBEDDER rule is needed. Embedder authority was checked once, when the space was created; retrieval through an existing space runs its configured embedders on the space's behalf.

3. Test the Boundary

Confirm the key retrieves from the intended space:

GOODMEM_API_KEY="gm_..." goodmem memory retrieve \
  --space-id $SPACE_ID "escalation procedure"

Then confirm it does nothing else. Listing spaces requires LIST_SPACE, which is not in the ceiling:

GOODMEM_API_KEY="gm_..." goodmem space list

This fails with PERMISSION_DENIED even though you — the subject — can list spaces fine. The ceiling is doing its job.

4. Issue an Ingestion Key

An ingestion pipeline needs to add memories to a space and nothing more. CREATE_MEMORY targets the space:

goodmem apikey create \
  --authority-mode scoped \
  --ceiling CREATE_MEMORY:EXACT:SPACE:$SPACE_ID \
  --label purpose=nightly-ingest

This key can write to the space but cannot read, search, or delete anything in it. A pipeline compromise leaks the ability to insert documents, which is recoverable, rather than the ability to read them, which is not.

5. Add a Validity Window

Both bounds are RFC3339 timestamps, immutable after issuance. The key works from --valid-from (inclusive, defaults to the moment of issuance) until --expires-at (exclusive, defaults to never):

goodmem apikey create \
  --authority-mode scoped \
  --ceiling CREATE_MEMORY:EXACT:SPACE:$SPACE_ID \
  --expires-at 2026-12-01T00:00:00Z \
  --label purpose=q4-migration

An expiring key turns rotation from a policy into a deadline. Since neither bound can be edited, extending access means issuing a replacement key.

6. When Issuance Is Refused

At issuance, every ceiling rule must fit within two things: what the subject is currently allowed to do, and what your issuing request is currently allowed to do. A ceiling can attenuate authority; it cannot manufacture it.

  • If your issuing credential does not cover a rule — say you hold a scoped key yourself and ask for a ceiling beyond it — the server returns PERMISSION_DENIED: Issuing credential does not cover every requested ceiling rule.
  • If the subject's live authority does not cover a rule, the server returns FAILED_PRECONDITION: Subject authority does not cover every requested ceiling rule.

There is no way to widen an existing key. If the ceiling turns out too narrow, issue a new key with the right rules and revoke the old one.

7. Keys for Other Subjects

--subject sets which principal the key authenticates as. Human keys are self-issued, so getting another person their first key goes through enrollment. The --subject flag exists for service identities: workload keys must be scoped, and issuing one requires MANAGE_ACCESS on that service identity. The full production pattern — durable identity, scoped keys, rotation that survives staff turnover — is in Set Up a Service Identity.

8. Revoke When Done

goodmem apikey delete 123e4567-e89b-12d3-a456-426614174000

Revocation is permanent and takes effect immediately. The row is retained for audit, so the key still appears in goodmem apikey list as inactive; it will never authenticate again. If a workload still needs access, issue its replacement key before revoking the old one.

See Also