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 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
{
"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
}
{
"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:
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:
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:
Do not share private keys, seed phrases, JWTs, API tokens, full config files, or unredacted logs.
See also: