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:
- CLI generates a fresh PKCE verifier + S256 challenge, plus a CSRF state token.
- CLI binds a one-shot HTTP listener on
127.0.0.1— the first free port from8765–8769. - 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). - You click Authorize. The browser redirects to
http://127.0.0.1:<port>/callback?code=...&state=.... - The local listener catches the callback, validates the state matches what was sent, then renders a "✓ Logged in — return to your terminal" page.
- CLI exchanges the authorization code + PKCE verifier for an access token via
<api>/oauth/token. - CLI calls
<api>/api/v1/profileto capture your name/email forwhoami. - 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:
- CLI prints the authorize URL.
- You open it on any device (your laptop, your phone, a teammate's machine).
- 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. - You copy the value of
code=from the address bar of that error page. - You paste it into the terminal where the CLI is waiting.
- 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:
--tenant <slug>flag on the commandtenant = "acme"in~/.autocom/config.toml- 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.