SC26AI agents lab + dinner on the river · Nov 17
Parallel Works

Authentication for CLI and scripts

Use pw auth for work you run yourself. Use an API key for a scheduled job or service that must run without someone signing in again. A script's runtime matters, but so does who will be there when its credentials expire.

Choose a method

What you need to doUseWhat happens over time
Work in a terminal on your computerBrowser sign-in: pw authThe CLI renews access until the sign-in expires or is revoked.
Work over SSH or on a computer without a browserDevice sign-in: pw auth --deviceYou approve in a browser on another device; renewal works like browser sign-in.
Run a notebook, analysis, or long-running script yourselfYour saved sign-in: CLI commands or an SDK created from credential configEach tool obtains fresh access tokens as needed.
Run CI, cron, a scheduled job, or a persistent serviceAn API key supplied through PW_API_KEY or a dedicated contextThe key does not renew. Replace it before its chosen expiration.
Make a one-off API call from a signed-in computerpw auth token --printThe printed access token expires; ask the CLI for another before a later call.

Browser and device sign-in both use your normal platform sign-in, including SSO and MFA. Device sign-in still requires a person to approve it; it is not an unattended login method. SSH keys authenticate SSH connections to clusters, not CLI or REST API requests. See account authentication for SSH keys and MFA settings.

Browser and device sign-in

Replace cloud.parallel.works with your platform's host:

pw auth cloud.parallel.works

For a remote terminal or headless computer:

pw auth --device cloud.parallel.works

Open the address printed by the CLI on a device with a browser. Enter the code and check that the page names the computer you are signing in from before approving. The resulting credentials are saved on the computer running pw, not the computer where you approved the code.

pw auth login is equivalent. The CLI also falls back to device sign-in when it cannot open a browser. If your organization disables device code sign-in, use browser sign-in on the same computer or an API key.

The CLI saves a context containing the account, platform, and credentials. Its default name is user@host. Use --context-name to name it, then select it explicitly in scripts:

pw auth --context-name research cloud.parallel.works
pw auth whoami --context research
pw api --context research buckets

How long a sign-in lasts

The current platform issues access tokens valid for one hour. The CLI renews them before expiry using a refresh token. That refresh token expires after 30 days without renewal, and a sign-in requires authentication again after at most 90 days, even with regular use. Signing the device out or an administrator revoking access can end it sooner.

These limits are why a renewable sign-in suits a long analysis you run yourself, while a persistent unattended service needs an API key and a rotation plan. A running process does not keep a sign-in alive unless it actually requests renewed access.

Refresh tokens are kept in the OS credential store when available, or in the owner-only credentials file otherwise. Let pw manage them: the platform rotates refresh tokens, and reusing an old one revokes the sign-in's token chain.

Long-running scripts

Let the CLI or SDK obtain fresh tokens

For shell scripts, call pw directly. For endpoints without a dedicated command, pw api handles authentication and the platform URL:

pw api --context research buckets

For Go, Python, and TypeScript, use the SDK credential-config constructors after signing in with pw auth. The SDK handles OAuth access tokens and renewal automatically through the CLI, so your script does not need to copy tokens or implement refresh logic. It runs pw auth token --print -o json, caches the access token, and asks again shortly before it expires. Keep pw installed and available to the process, including after it has started. For example:

from parallelworks_client import Client
 
with Client.from_credential_config(context="research").sync() as client:
    response = client.get("/api/buckets")
    response.raise_for_status()

Reuse that client for later requests; it handles renewal. The process needs access to the same writable credentials directory and, when used, the same OS credential store as the sign-in. If the sign-in expires or is revoked, run pw auth --context-name research cloud.parallel.works again, then retry the failed work. Renewal does not make a script independent of the sign-in's lifetime.

Calling the API with curl

If a tool needs a bearer token, ask the CLI immediately before the request. This Bash example stops if obtaining a token fails and uses the named context's platform:

set -euo pipefail
unset PW_API_KEY PW_PLATFORM_HOST
export PW_CONTEXT=research
 
pw_host=$(pw auth identify-platform)
case "$pw_host" in
  http://*|https://*) pw_base_url="$pw_host" ;;
  *) pw_base_url="https://$pw_host" ;;
esac
pw_access_token=$(pw auth token --print)
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $pw_access_token" \
  "$pw_base_url/api/buckets"
unset pw_access_token

Repeat token acquisition for each later request, including inside a polling loop. For a client that caches tokens, pw auth token --print -o json returns access_token, token_type, and expires_in when the CLI knows the remaining lifetime. Renew before that lifetime runs out; use an SDK if you do not need to implement this yourself.

Avoid freezing a token at startup

Do not use export PW_API_KEY="$(pw auth token --print)" to keep a long-running script signed in. It copies one short-lived access token into the environment. PW_API_KEY overrides saved contexts, and the CLI prints its value as is rather than renewing it. A raw-token SDK constructor also keeps using the supplied token; it does not inherit the sign-in that produced it.

If you already exported a copied token, run unset PW_API_KEY before using your saved context again. API keys, including those created with the Token option in Account > Authentication, are fixed credentials: saving one in a context does not make it renewable.

Unattended jobs and key rotation

Create an API key for each automation so you can replace or revoke it independently. An API key acts with its owner's account access; a context name or separate credentials directory does not restrict its permissions.

For a one-off job, the Token option creates a short-lived API key lasting 1–24 hours. Choose the expiration to cover the job; this is the same API-key mechanism, with no renewal.

Have your CI secret store or service manager supply PW_API_KEY to the process. There is no need to run pw auth first:

set -eu
: "${PW_API_KEY:?Supply an API key through the job secret store}"
pw auth whoami
pw api buckets

An API key includes its platform host. An opaque access token from browser sign-in does not; if you deliberately supply one through PW_API_KEY, also supply PW_PLATFORM_HOST when there is no saved context identifying the platform. It still will not renew.

By default, an API key's chosen expiration must be within 730 days. The Maximum API Key TTL policy can change that limit; non-expiring keys are available only when the policy is Unlimited. API keys never renew automatically, regardless of their chosen lifetime.

Before a key expires:

  1. Create a replacement and update the job's secret store or dedicated saved context.
  2. Restart a persistent process or recreate its SDK client so it reads the replacement. Changing a secret does not update the environment or client already held by a running process.
  3. Verify the job works with the new key, then delete the old key in Account > Authentication.

For cron, schedulers, and service managers, configure PATH and credentials in the job's environment; do not rely on your interactive shell startup files. When using a saved context, set an absolute PW_CREDENTIALS_DIR and PW_CONTEXT, and run the job as the OS user who owns those credentials.

Select an account without changing other work

CLI API requests and SDK clients created from credential config choose credentials in this order:

  1. PW_API_KEY, if nonempty.
  2. An explicit --context flag or SDK context option.
  3. PW_CONTEXT.
  4. The saved current context.

pw context use changes the saved default for other commands using the same file. Prefer --context for one command, or PW_CONTEXT inside a script or subshell:

(
  unset PW_API_KEY PW_PLATFORM_HOST
  export PW_CONTEXT=research
  pw auth whoami
  pw api buckets
)

Use pw context list to inspect saved contexts. A selected context can still be overridden by PW_API_KEY, so pw auth whoami is the better check for the account an API request actually uses. Unset an old PW_PLATFORM_HOST override when returning to the platform saved in your context.

Isolate credentials with PW_CREDENTIALS_DIR

Use contexts to switch accounts within one credentials file. Use PW_CREDENTIALS_DIR when a job, container, test, or remote host should have a separate file and its own current context.

ConfigurationCredentials file
Default$HOME/.config/pw/credentials
Absolute XDG_CONFIG_HOME set$XDG_CONFIG_HOME/pw/credentials
PW_CREDENTIALS_DIR set$PW_CREDENTIALS_DIR/.credentials

The override takes a directory, not a filename. The filename under the override is .credentials, including the leading dot. It takes precedence over XDG_CONFIG_HOME and disables legacy migration and fallback to ~/pw/.credentials. An empty directory starts with no saved contexts. Merely pointing it at $HOME/.config/pw will not select the usual credentials file because the names differ.

It changes credential storage for the CLI and the SDK credential-config constructors. It does not move the CLI's settings, cache, or state, bypass PW_API_KEY, or change account permissions. Use an absolute path: a relative path changes meaning when the job's working directory changes.

Give a script its own sign-in

Sign in afresh in a separate directory instead of copying a live sign-in:

(
  unset PW_API_KEY PW_CONTEXT PW_PLATFORM_HOST
  export PW_CREDENTIALS_DIR="$HOME/.config/pw-identities/analysis"
  pw auth --context-name analysis cloud.parallel.works
  pw auth whoami --context analysis
)

Use that directory and context every time you run the script:

(
  unset PW_API_KEY PW_PLATFORM_HOST
  export PW_CREDENTIALS_DIR="$HOME/.config/pw-identities/analysis"
  export PW_CONTEXT=analysis
  python analysis.py
)

Here, analysis.py is your script using Client.from_credential_config(). The subshell keeps these overrides out of your normal terminal session. For one command, you can also prefix it with PW_CREDENTIALS_DIR="/absolute/path" PW_CONTEXT=analysis, provided no PW_API_KEY override is set.

Use a temporary directory for a job

If a tool expects saved CLI credentials, load an API key from a secret file into a fresh directory. In this Bash example, /run/secrets/pw-api-key is the secret file supplied by your runner:

(
  set -eu
  unset PW_API_KEY PW_CONTEXT PW_PLATFORM_HOST
  pw_job_credentials=$(mktemp -d)
  trap 'rm -rf "$pw_job_credentials"' EXIT
  export PW_CREDENTIALS_DIR="$pw_job_credentials"
 
  pw auth --with-api-key --context-name job < /run/secrets/pw-api-key
  pw api --context job buckets
)

The trap removes the local credentials on exit. It does not revoke the API key; delete the key in Account > Authentication when it is no longer needed. Prefer injecting PW_API_KEY directly when a saved file is unnecessary.

Containers, shared homes, and remote hosts

  • Protect the directory. Keep credentials outside your repository and container image. Use a directory owned by the runtime user with mode 0700, and a credentials file with mode 0600. Avoid sudo pw auth against another user's directory.
  • Allow renewal to write. A browser or device sign-in updates its credentials file when it renews. A read-only mount cannot support that. Mount a writable directory, not only a single file, because updates replace the file atomically.
  • Do not copy a live sign-in to another machine or container. The file can refer to a refresh token in the original OS keychain. Even without a keychain, independent copies can reuse an already rotated refresh token and revoke the sign-in. Sign in separately on the destination or use an API key.
  • Use a separate sign-in per host when home directories are shared. For example, set PW_CREDENTIALS_DIR="$HOME/.config/pw-identities/$(hostname)" before signing in and running commands on each host. The CLI coordinates local refreshes through its cache, but independent hosts must not compete to renew one sign-in. If network filesystem locks stall, use an absolute, user-owned local XDG_CACHE_HOME, consistently for all processes sharing that host's sign-in.

Sign out and troubleshoot

Run pw auth logout with the same credentials-directory environment to revoke and remove a browser or device sign-in. Each sign-in also appears under Settings > Connected apps. Deleting a credentials file alone does not revoke it. For an API-key context, logout only removes the local context; delete the key in Account > Authentication to revoke it.

SymptomCheck and next step
The wrong account is used, even with --contextCheck whether PW_API_KEY is set without printing its secret value. Unset it to use the context, then run pw auth whoami.
It works at first, then fails after roughly an hourLook for a copied access token in PW_API_KEY or a raw-token SDK constructor. Use a saved sign-in and the credential-config constructor.
A saved sign-in cannot renewCheck pw is on the job's PATH, the credentials directory is writable, and the OS credential store is accessible. If the sign-in expired or was revoked, sign in again in that same directory and context.
A context disappears after setting PW_CREDENTIALS_DIRCheck the absolute directory and the .credentials filename. The override does not search your default credentials file.
A job works in your terminal but fails in cron or a containerCheck its OS user, PATH, PW_CONTEXT, PW_CREDENTIALS_DIR, and secret injection. Its environment and keychain access may differ from your shell.
An API key expiredCreate a replacement, update the secret, and restart processes that hold the old value. pw auth token --print cannot extend its lifetime.