Appearance
Rotate service API tokens
API tokens (psk_…) authenticate a workload as a User or ServiceIdentity. plexctl identity-tokens wraps /v1/auth/tokens. The plaintext is shown exactly once — capture it on issue/rotate.
Prerequisites
- An authenticated session — see Log in with plexctl.
- The principal UUID the token binds to.
Steps
Issue a token
shell
plexctl identity-tokens issue \
--identity-ref service:<service-uuid> \
--env-prefix prod \
--ttl 720h
# WARNING: this is the only time this plaintext will be displayed
# psk_prod_…
# ID ENV CREATED_AT EXPIRES_AT LAST_USED_AT ROTATED_AT
# … prod … … - ---identity-ref is user:<uuid> or service:<uuid>. The response prints the plaintext once under a one-time-plaintext banner; pipe it straight to the consuming secret store.
List and revoke
shell
plexctl identity-tokens list
plexctl identity-tokens delete --id <token-uuid>list never returns plaintext.
Rotate a token
shell
plexctl identity-tokens rotate --id <token-uuid>Rotate returns a new token with its own id and prints its plaintext once. Roll the new value out before the response leaves your terminal. The old plaintext keeps authenticating until the rotation_deadline the command prints, 48 hours after the rotation; after that only the new plaintext works.
Rotate refuses a token that is revoked, expired, or already rotated, and plexctl exits 1. A token rotates once: to rotate again, rotate its successor (the id the previous rotate printed).
Recover a rotation that left no successor
If rotate fails with a server error, the server may have marked the token as rotated without minting its successor. list then shows the token with rotated_at set, no new token appears, and a second rotate answers 409. The old plaintext still works until its sunset_at. Issue a new token from an interactive session, roll it out, then revoke the old one:
shell
plexctl identity-tokens issue \
--identity-ref service:<service-uuid> \
--env-prefix prod \
--ttl 720h
plexctl identity-tokens delete --id <old-token-uuid>Revoke a successor minted from a revoked token
Older server versions rotated a revoked token and minted a successor for it. That successor stays live: list shows it like any other live token, without revoked_at or sunset_at, and the Tokens tab in the Console (Identities → the service identity → Tokens) shows it as Active. To find one, look for a token whose revoked_at is earlier than its rotated_at; its successor is the token whose created_at equals that rotated_at. Revoke the successor unless you mean to keep it:
shell
plexctl identity-tokens delete --id <successor-uuid>A Domain admin can also revoke it from the Tokens tab. The tab issues, rotates, and revokes a service identity's tokens, and the server refuses a rotation there for the same reasons it refuses one from plexctl.
Mint an OAuth2 service token
shell
plexctl identity-tokens issue-service \
--client-id <client> \
--grant-type client_credentials \
--client-secret @/tmp/client-secret \
--scope "domains:read"
# TOKEN_TYPE EXPIRES_IN SCOPE ACCESS_TOKEN
# Bearer 3600 domains:read ***Verification
shell
plexctl identity-tokens list --output json \
| jq '.items[] | {id, rotated_at, sunset_at, revoked_at}'
# {
# "id": "<successor-uuid>",
# "rotated_at": null,
# "sunset_at": null,
# "revoked_at": null
# }
# {
# "id": "<token-uuid>",
# "rotated_at": "…",
# "sunset_at": "…",
# "revoked_at": null
# }After a rotation the successor is a separate entry with a new id. The rotated-from entry carries rotated_at and sunset_at, the instant its plaintext stops authenticating. revoked_at is set only on a revoked token. An unset key is absent from the output, and jq prints it as null.
See also
- Give a machine its own identity — the hands-on lesson that authenticates a ServiceIdentity and mints its first token, if this is new to you.
- Run behind a reverse proxy — required when the API is fronted by TLS termination.
../../reference/cli/plexctl/identity-tokens.md— every flag and exit code.