Enrollment tokens & scopes
The enrollment token is the identity pillar of Postern — the “scoped key that creates up to N mailboxes without the master key.” It is a capability token: it carries only the access it was granted, and that access is enforced server-side, not on trust.
Anatomy of an enrollment key
Section titled “Anatomy of an enrollment key”A minted enrollment key looks like pk_enroll_<id>_<secret>. The raw value is shown once; Postern
stores only its SHA-256 hash and compares in constant time. A key carries:
| Property | Meaning |
|---|---|
label | Human-readable name for the console (e.g. “support-bot bootstrap”). |
scopes | The capabilities it can mint into agent keys: mailbox:create, mailbox:read, mailbox:send. |
allowed_domains | The domains mailboxes may be created on. Empty = any org domain. |
max_mailboxes | The hard cap N on how many mailboxes this key may ever mint. |
used_count | How many it has minted so far. At max_mailboxes, the key is exhausted. |
reusable | Whether one key can mint many agents/mailboxes, or is single-use. |
expires_at | When the key stops working, regardless of remaining quota. |
revoked | A kill switch — instant, isolated. |
The capability model
Section titled “The capability model”Postern’s capability model is inspired by Panocrypt’s: the token carries a high-entropy secret, but the server is the source of truth for the counter and revocation.
-
Mint. A human or org-admin call issues a key with scopes, allowed domains,
max_mailboxes, and an expiry. POST /v1/enrollment-tokens (console) -
Redeem. An agent redeems the key for a scoped agent key (
pk_agent_…), idempotent on a client-providedagent_handle. POST /v1/enroll -
Spend. Each
mailbox:createincrementsused_count. Atmax_mailboxesthe key is exhausted — a cloned key cannot exceed N, because the counter lives server-side. -
Revoke. Per-token and per-agent-key, instant, isolated. Killing one key never rotates others.
Scopes
Section titled “Scopes”Scopes are additive capabilities. A key grants a subset; the minted agent key can never exceed it.
| Scope | Grants | Typical use |
|---|---|---|
mailbox:create | Create new mailboxes (against the quota) | Provisioning agents |
mailbox:read | List/read messages and threads | Read-only monitors, OTP readers |
mailbox:send | Send and reply | Outbound/transactional agents |
scopes = mailbox:create, mailbox:read // can make inboxes + read, but never sendallowed_domains = (empty → any org domain)max_mailboxes = 20expires_at = +24hWhy this contains the blast radius
Section titled “Why this contains the blast radius”The motivating failure is a supply-chain compromise of an MCP host that was handed an org-wide key. Postern’s answer is structural: no org-wide key ever reaches an MCP host. The host gets only a single-agent, single-purpose, expiring enrollment key. If it leaks:
- it can’t exceed
max_mailboxes(server counter); - it can’t reach domains outside
allowed_domains; - it can’t do anything outside its
scopes; - it can be revoked instantly, in isolation, without touching any other agent;
- every action it took is attributable in the audit log.
- Agents — the principal a key binds to.
- Authentication & keys — the redeem flow.
- API · Enrollment — the
/v1/enrollcontract.