Skip to content

Authentication

Use this page when you are setting up Bullpen for the first time, checking whether a session is still valid, or collecting auth diagnostics for support.

Login Flow

Bullpen uses browser-based device login.

Start with read-only diagnostics when you are not sure whether you are already logged in:

bullpen status --output json
bullpen doctor auth --output json

bullpen status shows the installed version, environment, login state, and local credential/session evidence only. It does not prove active Polymarket trading access; use bullpen polymarket wallet-audit --refresh --include-order-credit --output json or bullpen fix --refresh for refreshed wallet/readiness evidence. doctor auth returns support-friendly JSON for expired sessions, missing local files, incomplete account state, credential-storage shape, and Turnkey resource errors.

Both commands may include a nullable session_recovery object. When present, branch on session_recovery.code, requires_login, safe_to_retry, and next_command. Do not start login, forced logout, or local file cleanup from human prose alone.

Example output
$ bullpen doctor auth --output json
{
  "status": "ok",
  "error_code": null,
  "credentials_valid": true,
  "token_valid": true,
  "token_expires_in_secs": 840,
  "refresh_token_expires_in_secs": 2400000,
  "keypair_valid": true,
  "wallet_ready": true,
  "onboarding_complete": true,
  "trade_auth_state": "ready",
  "trade_auth_blocked": false,
  "turnkey_signing_session_present": true,
  "turnkey_signing_session_expired": false,
  "pending_actions": [],
  "session_recovery": null,
  "remediation": null
}
$ bullpen status --output json
{
  "version": "0.1.114 (Alpha)",
  "environment": "production",
  "credentials": "file (~/.bullpen/credentials.json.enc)",
  "account": {
    "logged_in": true,
    "token_store": "file (~/.bullpen/credentials.json.enc)"
  },
  "health": {
    "logged_in": true,
    "token_valid": true,
    "token_expires_in_seconds": 840,
    "email": null,
    "polymarket_address": null,
    "wallet_kind": null,
    "clob_api_key_present": null,
    "clob_readiness_status": "not_checked"
  },
  "prediction_trading_readiness": {
    "status": "not_checked",
    "label": "Not checked",
    "detail": "Passive status does not collect wallet, CLOB, relayer, or order-credit evidence.",
    "next_command": "bullpen polymarket wallet-audit --refresh --include-order-credit --output json"
  },
  "session_recovery": null
}

Run login when diagnostics show no usable session, or when you are setting up a new profile:

bullpen login

The CLI prints a URL and code. Open the URL, enter the code, and finish login in the browser. The CLI stores the resulting credentials under your Bullpen data directory. It does not require you to paste secrets back into the terminal.

If the browser cannot open on the same machine, use the documented no-browser path and complete the device code flow from another browser:

bullpen login --no-browser

If an older local install has encrypted credentials but is missing the matching credential_salt.bin, run bullpen doctor auth --output json first and preserve the output if you need support to inspect copied-home state. Restore the matching salt first only if you need to keep the old local session. Otherwise run bullpen login; it moves unreadable local auth files aside and starts a fresh session. Use bullpen logout --force && bullpen login only as a last-resort local reset.

Session Model And Expiry

A logged-in session is made of three credentials with different lifetimes, which is why sessions can break even though you "are still logged in":

Credential Approximate lifetime What breaks when it expires
JWT access token ~15 minutes Refreshed automatically from the refresh token; you normally never notice.
Refresh token ~30 days Once gone, the CLI cannot mint new access tokens and asks you to log in again.
Turnkey signing session ~7 days Signing (buy/sell/wrap/withdraw and Solana swaps) starts failing while read-only commands may still work.

The common "I was away and now trading fails" case is almost always an expired refresh token or expired Turnkey signing session. Read-only diagnostics still work; the fix is to mint a fresh session with bullpen login.

The Turnkey signing-session case is distinct: doctor auth --output json reports it through turnkey_signing_session_present and turnkey_signing_session_expired. A signed command can fail even when the JWT and refresh token are still valid. Re-run bullpen login to mint a fresh signing session — you do not need to delete ~/.bullpen first.

Normal Customer Trading Auth

Normal customer trading uses your Bullpen session and JWT.

Polymarket CLOB buy/sell/limit order commands submit through Bullpen using your authenticated session. Gasless operations use the account's selected Safe/Proxy or Deposit Wallet route. If account wallet evidence is inconsistent, money-moving commands fail closed and ask for diagnostics.

On v0.1.107+ builds, when a Polymarket order submit reaches Bullpen with a locally stale JWT, the CLI refreshes the Bullpen session and retries the same idempotent order request once. If Bullpen still rejects the refreshed session, the CLI returns a support-safe authentication error without asking for extra customer configuration. This retry is for idempotent CLOB order submit paths. Re-run bullpen doctor auth --output json before starting a new login flow.

Auth refresh failures are separated by cause. If the refresh token itself is rejected, the CLI asks you to log in again. If refresh succeeds but local credential persistence fails, the CLI fails closed with a storage-focused error so unattended bots do not continue with stale credentials. If refresh fails due to a transient network or service problem, retry the command before starting a new login.

Hyperliquid trading uses wallet signing for normal order flows. Hyperliquid agent-wallet management is separate and should be used only when a command explicitly asks for it.

Credential Storage And Isolation

By default, Bullpen stores local configuration and credentials under ~/.bullpen.

Control Purpose
BULLPEN_HOME Override the Bullpen data directory. Credentials still resolve through this directory.
--config <path> Use a specific config.toml. The path fails closed if it does not exist.
BULLPEN_CONFIG Use a specific config file path when --config is not provided. The path fails closed if it does not exist.

The encrypted credential bundle is local state. credentials.json.enc cannot be decrypted without the matching local encryption metadata, including credential_salt.bin when present for that profile. Copying only credentials.json.enc to another machine or another BULLPEN_HOME is not a portable login backup.

status --output json and doctor auth --output json include a credential_storage object. Use it to distinguish encrypted credentials, legacy plaintext credentials, both files, no local credentials, and ephemeral test stores without decrypting or rewriting the credential files.

When isolating a test account or CI run, set both BULLPEN_HOME and BULLPEN_CONFIG so config and credentials stay together.

export BULLPEN_HOME="$PWD/.bullpen-test-home"
export BULLPEN_CONFIG="$BULLPEN_HOME/config.toml"
bullpen config init
bullpen login

For unattended bots and copied credential homes, use an absolute BULLPEN_HOME such as /var/lib/bullpen-bot. Relative values are rejected because they can point at different profiles under cron, systemd, Docker, or CI runners.

If you copy an encrypted credential home to another host, copy credentials.json.enc, credential_salt.bin, and keys/ together. Keep the same absolute BULLPEN_HOME on both hosts and set the same BULLPEN_USERNAME_OVERRIDE when the runtime OS username differs. Then run bullpen doctor deploy-auth --output json on the destination host before any unattended trading command.

Use a local persistent filesystem for unattended auth. Network filesystems, cloud-synced folders, and container volumes can work only after you validate them with bullpen doctor deploy-auth --output json and the release auth smoke in the same runtime environment. Do not assume copied credentials are portable across a different absolute home path, username component, or partially synced directory.

Keep the Bullpen home writable. Auth refresh is treated as successful only when the refreshed credentials are durably saved; if the CLI cannot persist the rotated session, it fails closed with a storage-focused error instead of silently leaving the next bot process with stale credentials.

Use bullpen doctor auth --output json inside the same environment block before running account or trading commands from the isolated profile.

For deterministic CI or release smoke runs that must not write the update-check cache, set BULLPEN_DISABLE_UPDATE_CHECK=1. This disables the background update checker only; it does not change auth, trading, or credential behavior.

Login Friction Checklist

Use the smallest next step that matches the symptom.

Symptom Safe next step Notes
You are unsure which account or environment is active bullpen status --output json Read-only. Confirms version, environment, and login state.
The browser did not open or is on another machine bullpen login --no-browser Safe. Prints the verification URL and device code.
The device code expired bullpen login Safe. Starts a fresh device-code login.
You were away and trading/signing now fails bullpen login Your refresh token (~30 days) or Turnkey signing session (~7 days) expired. Logging in mints a fresh session. Run bullpen doctor auth --output json first to confirm.
doctor auth shows turnkey_signing_session_expired: true bullpen login The 7-day Turnkey signing session expired; signing fails even when the JWT is still valid. Do not delete ~/.bullpen first.
Auth diagnostics mention missing or corrupt encrypted credentials or salt files bullpen login Starts a fresh session by moving unreadable local auth files aside. Run bullpen doctor auth --output json first if you need support to inspect copied-home state; restore the matching salt first only if you need to keep the old local session.
You choose to reset unrecoverable local auth state bullpen logout --force && bullpen login Last-resort destructive local reset. Clears local credentials before re-login.
doctor auth says local keypair repair is applicable bullpen doctor auth --repair --yes Destructive local keypair repair. Use only when the diagnostic output names this repair.
doctor auth reports incomplete account state after a fresh login bullpen verify-email Safe account-completion step; see the generated reference for exact options.

Do not delete the whole Bullpen home directory as the first fix. That can remove logs, config, local keys, and wallet-routing evidence that support may need.

Recovery Commands

Use the smallest recovery command that matches the failure.

Situation Command
Check current auth state bullpen doctor auth --output json
Re-run ordinary device-code login bullpen login
Refresh an expired session after time away (refresh token or Turnkey signing session) bullpen login
Restore signing when turnkey_signing_session_expired is true bullpen login
Clear local credentials bullpen logout
Clear corrupted local credentials when normal logout cannot load them bullpen logout --force
Back up and remove a corrupt local keypair file when doctor auth says repair is applicable bullpen doctor auth --repair --yes
Verify email if account access is incomplete bullpen verify-email
Confirm installed version and platform gates bullpen status --output json

bullpen doctor auth --repair --yes is destructive and support-facing: it backs up and removes the corrupt local keypair file only when the diagnostic says that repair is applicable, and still requires the typed REPAIR confirmation prompt. Use read-only doctor auth --output json first. Missing or corrupt encrypted credentials and salt files use the login recovery path above.

bullpen logout --force --output json returns a top-level server_warning field plus a force_wipe object. The JSON redacts local absolute paths while still marking the operation as destructive. Human output still names the local files it is clearing for the current machine, but support tickets should prefer the JSON form when path disclosure is not needed.

Do not delete ~/.bullpen as the first recovery step. That also removes local config, keys, and logs that may help support diagnose the issue.

Support Capture

For support tickets, include command output from the same machine and account that saw the failure:

bullpen --version
bullpen status --output json
bullpen doctor auth --output json

Do not share private keys, seed phrases, JWTs, API tokens, full config files, or unredacted logs.

See also: