Skip to main content
Photon CLI signs you in with the OAuth 2.0 device authorization grant (RFC 8628). You approve the login in a browser, and the CLI stores the resulting tokens in your operating system’s credential manager.
Where no one can approve a sign-in, as in CI, put a Photon key in PHOTON_API_TOKEN instead. See which credential to use.

Which credential to use

Each kind of key fits one use. Whichever you put in PHOTON_API_TOKEN, give it only what its commands need:

Use a key from the environment

When PHOTON_API_TOKEN holds a key, every command sends that key:
  • It wins over a stored sign-in, which stays as it is.
  • The CLI saves no credential, no sign-in metadata, and no operation journal for it. So a failed write can’t be replayed with photon operation replay. Its error’s next step repeats the command with the same --idempotency-key instead. photon org use still saves the organization it selects, under the key’s ID, or a digest of a value with no ID (never its secret).
  • The key doesn’t choose a project or an organization. Pass --project or set PHOTON_PROJECT_ID (and --org or PHOTON_ORGANIZATION_ID). Without a project, a project command exits with code 2 and PROJECT_NOT_SELECTED.
  • When Photon refuses the key as missing, expired, or revoked (HTTP 401), the command exits with code 4, and its next step is to replace the key in PHOTON_API_TOKEN. When Photon refuses the key for the request (HTTP 403), often because it’s the wrong kind of key for the command, the command exits with code 1. The error names the key’s kind and the variable it came from, and its detail keeps Photon’s own words, which may name the kinds the request accepts. Commands that handle secrets, such as photon account service-key create, leave Photon’s words out.
  • photon login refuses while the variable is set (exit code 2, AUTH_ENVIRONMENT_KEY_SET). photon logout still removes the stored sign-in, and warns that the key is still in use until you unset the variable.
  • An empty value counts as unset.
In GitHub Actions, with a service identity API key that holds only project:read, the one permission listing webhooks needs:
photon auth status names the key’s source, kind, and ID, never its secret. It checks an account service key with Photon. A project API key or a service identity API key reports unverified, because no request checks those keys without a project.

Sign in

1

Run photon login

The CLI first checks where it can store the sign-in: your operating system’s credential manager, or a plain-text file when it can’t use one. See where credentials are stored.
2

Approve in the browser

The CLI prints two links on stderr before it waits: the verification URL with a user code to enter, and a link that already contains the code. Then it opens your browser at the second link. It opens no browser with --no-browser or when CI is set, and says so; open either printed link on any device.
3

Wait for approval

The CLI polls at the interval Photon selects and backs off when asked to. A spinner shows progress in an interactive terminal, and is omitted in --json mode.
4

Credentials are stored

Only after you approve the login does the CLI write the access token and rotating refresh token, to the credential manager or the file.
Denial, expiry, and protocol errors end the login immediately. An expired code exits with code 4 and photon login as its next step. Pressing Ctrl-C aborts the wait, stores nothing, and exits with code 130. Useful variants:
photon login doesn’t sign in again when your existing session is already healthy. It prints who is signed in and names photon login --force for signing in as a different account on a Next: line on stderr, with or without --json. With --force, the old session stays usable throughout the new device flow and is replaced only once the new credential is stored.

Where credentials are stored

The CLI stores the sign-in in your operating system’s credential manager: On Linux, install the libsecret command-line tools and make sure a Secret Service keyring is running and unlocked. Where there is no usable credential manager (as in most containers and CI runners), or it refuses to save a new sign-in (a locked keyring), the CLI saves the sign-in in plain text to a file in the configuration directory instead (credentials.json, or a file under credential-entries/ with --service-key) and prints a warning that names the file. --insecure-storage uses that file even when a credential manager is there. On POSIX systems the CLI creates it with mode 0600 inside a 0700 directory, and writes it atomically so an interrupted command cannot leave a partial credential behind. Non-secret metadata — the API origin, which storage backend is in use, your cached identity, and timestamps — lives in auth.json alongside it:
If the CLI finds an unknown or malformed credential schema, it refuses to overwrite it. photon auth status then reports storage as unavailable, and photon logout --force removes the local files it recognizes while warning that an entry may remain in your secure store.

Refresh and concurrent commands

You do not need to refresh anything by hand. The CLI renews the access token 60 seconds before it expires, and always reads your identity and authorization from Photon rather than trusting the token’s contents. You can run several photon commands at once. They coordinate through a lock, so only one process performs the exchange and the others pick up the rotated tokens. A transient refresh failure leaves your credentials intact and asks you to retry; only a rejected refresh token deletes them and requires a new login.

Session commands

photon logout is local-only. Photon’s authentication service has no revocation endpoint, so signing out does not revoke the remote session.

Limits

The CLI stores one signed-in account. Named profiles and token import and export aren’t supported.