Appearance
plexctl bootstrap-token
Synopsis
plexctl bootstrap-token is the CLI surface for the per-Project BootstrapToken aggregate. It wraps the four /v1/projects/{project_id}/bootstrap-tokens endpoints — IssueBootstrapToken, ListBootstrapTokens, GetBootstrapTokenMetadata, and RevokeBootstrapToken — so an operator can mint, page, inspect, and retire the single-use bearer credentials a fresh Node or Bridge presents on its very first call to plexsphere.
The plaintext is shown exactly once on the issue response. In text mode the CLI prefixes the plaintext with the one-time-plaintext banner (# WARNING: this is the only time this plaintext will be displayed) on stdout; in json / yaml mode the typed BootstrapTokenIssueResponse body is rendered verbatim so a script consumer keeps the structured fields. The list and get subcommands return metadata only — the plaintext is never returned again by the API after issuance.
For the bounded-context reference (state machine, plaintext format, Argon2id parameters, audit contract) see ../../contexts/identity/bootstrap-tokens.md. For the curl-based runbook that predates this CLI surface see ../../how-to/enrolment/issue-a-bootstrap-token.md.
Invocation
text
plexctl bootstrap-token <subcommand> [flags]The four subcommands are enumerated below.
plexctl bootstrap-token issue
Mints a new BootstrapToken via POST /v1/projects/{project_id}/bootstrap-tokens and renders the plaintext exactly once. The --ttl flag carries a Go duration (5m, 1h, 24h); the server enforces the [300, 86400] seconds range and rejects out-of-range values with 400 Bad Request.
plexctl bootstrap-token list
Pages the per-Project token roster via keyset cursor. The response body carries metadata only — id, project_id, kind, env_prefix, issued_at, expires_at, consumed_at, revoked_at, issued_by_user_id — and the CLI projects an extra STATE column derived from the optional terminal timestamps so an operator can spot a consumed or revoked row at a glance.
plexctl bootstrap-token get
Returns the metadata view of a single token by --token-id. Useful for confirming a redemption landed (consumed_at populated) or a revoke took effect (revoked_at populated).
plexctl bootstrap-token revoke
Marks a BootstrapToken revoked. The server stamps revoked_at = now on the row and emits a single audit Entry per call. The SQL layer's Revoke is idempotent (gates on revoked_at IS NULL) but the audit middleware writes one Entry per call so re-revocation by the same operator is still visible in the stream.
Flags
plexctl bootstrap-token issue
| Flag | Type | Required | Default | Description |
|---|---|---|---|---|
--project | UUID | yes | — | Owning Project UUID. |
--kind | enum | yes | — | Redemption surface: node | bridge. The Validator on the redemption side rejects a bridge token presented at the Node endpoint with ErrKindMismatch. |
--env-prefix | string | yes | — | Environment segment encoded into the plaintext. MUST match ^[a-z]+$; the server enforces the same regex. |
--ttl | duration | yes | — | Token lifetime (e.g. 5m, 1h). Bounded server-side by [5m, 24h]. |
plexctl bootstrap-token list
| Flag | Type | Required | Default | Description |
|---|---|---|---|---|
--project | UUID | yes | — | Owning Project UUID. |
--limit | int | no | server default | Maximum items per page. 0 lets the server pick. |
--cursor | string | no | — | Continuation token from a previous call's next_cursor. |
plexctl bootstrap-token get
| Flag | Type | Required | Default | Description |
|---|---|---|---|---|
--project | UUID | yes | — | Owning Project UUID. |
--token-id | UUID | yes | — | BootstrapToken UUID (matches the Location header returned by issue). |
plexctl bootstrap-token revoke
| Flag | Type | Required | Default | Description |
|---|---|---|---|---|
--project | UUID | yes | — | Owning Project UUID. |
--token-id | UUID | yes | — | BootstrapToken UUID. |
Persistent flags inherited from root
--server, --profile, --token-file, --output, --yes, --reveal-secrets. The --reveal-secrets flag is inert for this command — the plaintext is always rendered exactly once on issue because the server never returns it twice. See plexctl.md for the canonical persistent-flag list.
Exit codes
plexctl collapses every failure into the taxonomy below; the single source of truth is exitCodeFor in ../../../cmd/plexctl/app.go.
| Code | Reachable | Meaning |
|---|---|---|
0 | yes | The API returned the expected status (201 for issue, 200 for list / get, 204 for revoke). |
1 | yes | Runtime / API error: transport failure, unexpected status code, or a malformed response body. |
2 | yes | Flag-parse / misconfiguration: missing required flag, malformed UUID, unknown --kind value, or non-positive --ttl. |
3 | yes | Missing or insecure credentials, or 401 Unauthorized from the API. |
4 | yes | Permission denied: 403 Forbidden (the operator lacks project:manage for issue/revoke, or project:deploy for list/get). |
64 | no | Not reachable — bootstrap-token is fully implemented and never returns *NotImplementedError. |
Examples
Issue a Node token (text mode shows the one-time plaintext)
shell
export PLEXSPHERE_URL="${PLEXSPHERE_URL:-https://localhost:8080}"
plexctl bootstrap-token issue \
--server "${PLEXSPHERE_URL}" \
--project 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0 \
--kind node \
--env-prefix prod \
--ttl 1htext
# WARNING: this is the only time this plaintext will be displayed
psb_prod_aebagbafaydqqbrhibbsa3kqaq_node_xxxxxxxxxxxxxxxxxxxxxxxxxx
token_id: 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a1
issued_at: 2026-05-01T10:00:00Z
expires_at: 2026-05-01T11:00:00ZCapture the plaintext immediately and hand it out-of-band to the redeeming Node. The plexsphere API itself is the only surface that ever holds the plaintext; copying it through chat, email, or shell history defeats the single-use guarantee.
Issue a Bridge token as JSON for a CI pipeline
shell
plexctl bootstrap-token issue \
--server "${PLEXSPHERE_URL}" \
--project 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0 \
--kind bridge \
--env-prefix staging \
--ttl 15m \
--output jsonjson
{
"token_id": "0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a2",
"token": "psb_staging_aebagbafaydqqbrhibbsa3kqaq_bridge_xxxxxxxxxxxxxxxxxxxxxxxxxx",
"issued_at": "2026-05-01T10:00:00Z",
"expires_at": "2026-05-01T10:15:00Z"
}The token field appears in the response body once. Pipe the output into a sealed-secret pipeline and never persist the JSON document to disk.
List outstanding tokens for a Project
shell
plexctl bootstrap-token list \
--server "${PLEXSPHERE_URL}" \
--project 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0text
ID PROJECT ENV KIND ISSUED_AT EXPIRES_AT STATE
0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a1 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0 prod node 2026-05-01T10:00:00Z 2026-05-01T11:00:00Z live
0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a2 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0 staging bridge 2026-05-01T10:00:00Z 2026-05-01T10:15:00Z consumedPermission denied on revoke (exit 4)
shell
plexctl bootstrap-token revoke \
--server "${PLEXSPHERE_URL}" \
--project 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a0 \
--token-id 0190a8b8-a0c0-7a0a-8a0a-a0a0a0a0a0a1
# stderr: plexctl: 403 Forbidden: insufficient_relation (need project:manage or project:deploy)
echo $? # 4Cross-references
../../../api/openapi/plexsphere-v1.yaml—IssueBootstrapToken,ListBootstrapTokens,GetBootstrapTokenMetadata,RevokeBootstrapTokenoperation definitions and theBootstrapTokenIssueRequest,BootstrapTokenIssueResponse,BootstrapTokenMetadata,BootstrapTokenListschemas.../../contexts/identity/bootstrap-tokens.md— bounded-context reference: ubiquitous language, kind matrix, TTL policy, state machine, plaintext format, Argon2id parameters, nonce-set algorithm, audit contract, threat model.../../how-to/enrolment/issue-a-bootstrap-token.md— operator how-to usingcurlagainst the same four operations.../../../cmd/plexctl/commands/bootstrap_token.go— source of truth for the cobra command, the one-time-plaintext banner rendering, the metadata table projection, and the state derivation.