Skip to content

Bootstrap tokens

A bootstrap token authenticates an agent's first WebSocket upgrade. It is short-lived (default 24 h), single-use, and is replaced by an mTLS client certificate after the first successful redemption. After that the token is gone forever — even if you copy it out of the database, Ampora hashes the token at rest and only matches against the hash.

Issuing a token

Single-token flow (manual onboarding):

  1. Settings → Tokens → Issue token.
  2. Set:
  3. Label — free text, used in audit logs.
  4. TTL — between 15 minutes and 168 hours (7 days). Default 24 h.
  5. Tenant — when running multi-tenant Hard Isolation. The redeemed cert is bound to this tenant.
  6. Group (optional) — if set, the agent lands directly in that group on first connect; otherwise it stays unassigned.
  7. Click Issue. The plaintext token is shown once.

The token format is amp-bs.<base32>.<crc> — it is self-describing so a quick visual check tells you whether you copied it intact.

Single-use, by design

The redemption flow is transactional: the same token cannot be redeemed twice. The hash row is deleted in the same transaction that creates the agent identity and issues the cert. If the connection drops between "cert issued" and "agent stores cert", the agent must request a fresh token — the previous one is gone. This is why bootstrap is a manual / ops moment, not part of agent steady-state.

Pools

For automation flows where you need to onboard hundreds of agents (cattle, not pets), use a token pool:

  • A pool exposes a small admin API that issues short-lived tokens on demand without the operator clicking through the UI for every one.
  • Each pool has its own admin secret, its own per-issued-token TTL, an optional default group, and an optional tenant scope.
  • Issued tokens are still single-use; the pool just automates the issuing part.

See ADR-040 – Bootstrap token pools for the protocol and threat model.

Creating a pool

  1. Settings → Tokens → Pools → New pool.
  2. Set name, default TTL, tenant scope, optional default group.
  3. Save. The page shows the pool admin secret once.

Issuing tokens from the pool

TOKEN=$(curl -fsS -X POST \
  -H "Authorization: Bearer ${POOL_ADMIN_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{"ttlMinutes":15}' \
  "https://AMPORA_HOST/api/tokens/pools/${POOL_ID}/issue" \
  | jq -r '.token')

echo "${TOKEN}"

Pipe TOKEN directly into the agent provisioning script. Never write the plaintext to disk.

Revoking a pool

Revoking a pool invalidates every token previously issued from it. Use this if the admin secret leaked. New agents that already redeemed tokens into mTLS certs are unaffected — those certs revoke separately via CRL/OCSP.

Revoking a single token

If a token leaks before being redeemed:

  • Settings → Tokens → find the row → Revoke.

Revoked tokens cannot be redeemed even within their TTL. The audit log records the revocation with actor and timestamp.

Rotating compromised material

Token compromise (one operator's clipboard, a leaked Slack message) should be treated like any secret leak:

  1. Revoke the token (UI or API).
  2. Rotate the pool's admin secret if it was a pool-issued token. The pool's "rotate admin secret" action invalidates every previously issued token.
  3. Audit-log review: which agents redeemed tokens from the affected pool in the leak window? Revoke the corresponding certs to be safe (the agent re-bootstraps cleanly after).

Auditing

Every of these produces an audit event:

  • Token.Issued — actor, label, TTL, tenant, optional group, pool source.
  • Token.Revoked — actor, reason if provided.
  • Token.Redeemed — what agent redeemed it, the cert thumbprint that came out, the source IP.
  • Pool.Created, Pool.AdminSecretRotated, Pool.Deleted.

Filter the audit log by entity type Token to see the full activity stream.

Why bootstrap-then-mTLS?

OpAMP itself does not mandate a trust model — it leaves the choice to the server. Ampora's choice is bootstrap-token-then-mTLS because it is:

  • Defendable — bootstrap tokens are short-lived; certs are long-lived but revocable; neither factor alone is sufficient post-bootstrap.
  • Air-gap-friendly — no dependence on external CAs, KMS-issuance coordination, or an out-of-band PKI.
  • Operationally lightweight — operators can issue tokens through a UI or a small API, without learning OpenSSL.

Alternatives we evaluated (long-lived shared secret, IP allowlist, externally-issued client cert) all failed at least one of those tests. See Threat model for the full reasoning.