Authentication

autocom auth login supports three flows. Use whichever fits your environment.

Flow Best for Network needed Browser needed
OAuth browser (default) Local laptops Yes Yes — opens automatically
OAuth no-browser SSH sessions, headless boxes Yes Any device — manual
Personal access token CI, scripts, automation Yes No

All three end with the same outcome: an OAuth access token (or PAT) stored in your OS keychain (go-keyring) — Keychain on macOS, Secret Service on Linux, Credential Manager on Windows. If no keychain is reachable (sandboxed containers), it falls back to ~/.autocom/credentials at mode 0600.

OAuth browser flow (default)

This is what autocom auth login does with no flags. It mirrors gh auth login.

autocom auth login --tenant acme

What happens:

  1. CLI generates a fresh PKCE verifier + S256 challenge, plus a CSRF state token.
  2. CLI binds a one-shot HTTP listener on 127.0.0.1 — the first free port from 8765–8769.
  3. CLI opens your default browser to <api>/oauth/authorize?response_type=code&.... You see the platform's normal OAuth approval page (same one third-party integrations use).
  4. You click Authorize. The browser redirects to http://127.0.0.1:<port>/callback?code=...&state=....
  5. The local listener catches the callback, validates the state matches what was sent, then renders a "✓ Logged in — return to your terminal" page.
  6. CLI exchanges the authorization code + PKCE verifier for an access token via <api>/oauth/token.
  7. CLI calls <api>/api/v1/profile to capture your name/email for whoami.
  8. Credentials are saved to the keychain.

You're done in ~10 seconds with one click in the browser.

Picking the OAuth client ID

The CLI needs to know which Passport OAuth client to authorize against. Three ways to provide it, in priority order:

autocom auth login --client-id <uuid>            # explicit flag
AUTOCOM_CLIENT_ID=<uuid> autocom auth login      # environment variable
autocom auth login                               # build-time default (most common)

Releases shipped via Homebrew / GitLab Releases bake the production client ID into the binary at link time (-X .../auth.DefaultClientID=<uuid>). Self-hosted deployments register their own OAuth client via php artisan passport:client --public --redirect="http://127.0.0.1:8765/callback,http://127.0.0.1:8766/callback,..." and ship a binary with that UUID baked in, OR distribute the UUID to users to set as an env var.

Localhost ports

The callback listener tries 8765, 8766, 8767, 8768, 8769 in order. All five must be registered as redirect URIs on the Passport OAuth client (Passport supports comma-separated redirect_uri lists). If the registered list is shorter, fewer ports are available and the login fails with "no callback port available."

What if the browser won't launch

The CLI tries $BROWSER first, then OS-default openers (open on macOS, rundll32 on Windows, xdg-open / sensible-browser / x-www-browser on Linux). If none work, it prints the URL and waits — paste it into a browser by hand, approve, and the local listener still catches the callback.

OAuth no-browser (paste-back)

For SSH sessions, headless containers, or any environment where the local-listener trick won't work because the browser can't reach localhost:

autocom auth login --no-browser --tenant acme

What happens:

  1. CLI prints the authorize URL.
  2. You open it on any device (your laptop, your phone, a teammate's machine).
  3. You approve. The browser tries to redirect to http://127.0.0.1:8765/callback?code=... — this hits a "connection refused" page on whatever device the browser is on. That's expected.
  4. You copy the value of code= from the address bar of that error page.
  5. You paste it into the terminal where the CLI is waiting.
  6. CLI exchanges the code + PKCE verifier (the verifier was generated locally; it never left the terminal) for an access token.

The "connection refused" page is annoying but the security model holds: the PKCE verifier is the only thing the token endpoint validates against, and it lives in the CLI process the whole time. An attacker who intercepts the code can't redeem it without the verifier.

A future platform improvement is to support redirect_uri=urn:ietf:wg:oauth:2.0:oob so the authorize page renders the code on a styled "your code is" page instead of a connection-refused error. The CLI is forward-compatible — when the platform supports it, no client changes needed.

Personal access token (CI, scripts)

Skip OAuth entirely. Use this in CI pipelines, GitHub Actions, scheduled jobs, or anywhere you can't (or shouldn't) involve a human:

# Pass the token directly
autocom auth login --with-token glpat-xxxxx --tenant acme

# Read from stdin (preferred — avoids putting the token in shell history)
echo $AUTOCOM_TOKEN | autocom auth login --token-stdin --tenant acme

# Or pass via env to one-off commands without persisting
# (not yet supported — see issue tracker)

PATs are minted from the platform UI: Settings → Security → Personal access tokens → Generate new token. Scope the token to the same permissions you'd grant a teammate.

The CLI validates the token against <api>/api/v1/profile before saving — bad tokens fail fast with exit 4.

Tenant resolution

Every command sends X-Tenant: <slug>. The slug is resolved in this order, first hit wins:

  1. --tenant <slug> flag on the command
  2. tenant = "acme" in ~/.autocom/config.toml
  3. The tenant captured at login time (creds.TenantID)

If you're a member of multiple tenants, list them with autocom tenants list and switch the default with autocom tenants use <slug>.

Multi-environment

Each environment is keyed by api_url in the credential store. Switch by setting the URL at login:

autocom auth login --api-url https://api.staging.autocom.io/api/v1 --tenant acme
autocom auth login --api-url https://api.autocom.wexron.io/api/v1   --tenant acme

# Run against either env
autocom --api-url https://api.staging.autocom.io/api/v1 orders list
autocom orders list                                                  # default = whatever's in config

Both PATs / tokens stay in the keychain side-by-side; there's no interference.

Logout

autocom auth logout                                    # forgets creds for the current api_url
autocom auth logout --api-url https://api.staging…    # specific environment

Logout deletes the credential record from BOTH the keychain primary and the file fallback. Config preferences (api_url, default tenant, output format) stay.

What's stored where

Data Location Permissions
Access token OS keychain (or ~/.autocom/credentials fallback) Encrypted by OS / 0600 file
Refresh token Same Same
User name + email Same — captured at login for offline whoami Same
Tenant slug Same + ~/.autocom/config.toml (the default) 0600 file
API URL ~/.autocom/config.toml 0600 file
PKCE verifier Process memory only — never written to disk

Token expiry

OAuth access tokens have a TTL set by the platform (default 1 hour for password/auth-code, configurable). When a token is within 30 seconds of expiring, whoami warns and the next API call returns exit 4 (credentials expired — run autocom auth login).

PATs typically have no exposed TTL — they're valid until you revoke them from the platform UI or via autocom auth logout.

Refresh-token support is wired but not yet automatic — a future release will silently refresh on expiry.

Troubleshooting

See Troubleshooting for the common issues — wrong client ID, port collision, browser won't launch, headless containers without a keychain.