Appearance
Log in with plexctl
plexctl login authenticates an operator with the RFC 8628 device grant and persists the bearer token (mode 0600) so later commands need no flags. plexctl whoami confirms the session.
Prerequisites
plexctlon$PATH— see Install plexctl.- A reachable control plane. For local work bring up the kind dev stack:
../../tutorials/set-up-local-plexsphere.md. - The
domain_id(UUIDv7) you authenticate into — discover it as below.plexctl loginresolves the Domain's single active IdP binding for you, so no binding id is needed unless the Domain has more than one active binding.
Steps
Discover the Domain id (local kind stack)
make dev seeds demo Domains, each with one active IdP binding. Read the Domain UUID straight from the dev Postgres StatefulSet:
shell
kubectl exec statefulset/postgres -- \
env PGPASSWORD=plexsphere psql -U plexsphere -d plexsphere -tAc \
"SELECT d.slug, d.id
FROM plexsphere.domains d
ORDER BY d.slug"The two columns are the Domain slug and the domain_id. Against a remote deployment, read it from plexctl domain list once any operator session exists.
Point plexctl at the server
shell
export PLEXSPHERE_URL="${PLEXSPHERE_URL:-https://localhost:8080}"Every command also accepts --server "${PLEXSPHERE_URL}" instead.
Run the device-code login
shell
plexctl login --domain-id <domain-uuid>plexctl prints a verification URL and a user code, then polls until the device code is approved and writes the returned token to the default profile (override with --profile-name <name>). Missing --domain-id exits 2. If the Domain has more than one active IdP binding, the server cannot disambiguate; pin one with --idp-binding-id <idp-binding-uuid>.
Re-running the command while the stored session is still live and still matches the requested Domain and scope keeps that session: no browser round trip happens, stdout reports Kept the existing session for profile "default" (subject <principal-uuid>). Pass --force to re-authenticate., and the command exits 0. Check the printed subject when the config file is shared — it is the principal you keep operating as. Pass --force when you want a fresh token anyway, and --min-remaining <duration> to set how much lifetime the stored session must have left (default 5m).
Approve the device code in a browser
Open the printed verification URL (the /v1/device?user_code=… link) in a browser. The control plane serves the approval page itself, so a bare stack needs no external dashboard:
- Signed out, the page starts the sign-in round-trip against the binding the device request resolved to and returns you to the same page once your identity provider authenticates you.
- Signed in, the page shows an Approve button. Approving flips the device request and the waiting
plexctlpoll receives its token.
If you reopen the link after approval (or after it expires), the page explains the request is no longer pending and points you back to plexctl login.
Verification
shell
plexctl whoami
# PRINCIPAL SCOPE SUBJECT DOMAIN ACR AMR
# user domain … … - -A populated row proves the token reaches the API and resolves to a principal. 401/missing credentials exits 3.
See also
../../reference/cli/plexctl/login.md— all flags and exit codes.../../reference/api/idp.md#sign-in-endpoint— the browserPOST /v1/auth/sign-inendpoint and its resolution branches, the contract behind the Approve page above.../../contexts/identity/idp.md— the device-code surface andIdPBindingaggregate.