Authenticate once, use credentials everywhere.

How it works

SigCLI opens a real browser for you to log in — any SSO, any site. It captures the session credentials, encrypts them locally, and makes them available to your scripts and AI agents on demand.

You log in once sig stores credentials Your tools use them (real browser, any SSO) (encrypted, ~/.sig/) (sig request / run / proxy)

No passwords in shell history. No tokens in your repo. No manual copy-paste.

Getting Started

Install

npm install -g @sigcli/cli

Requires Node 18+. Then run sig init to detect your browser and create the config file.

sig init

First login

Pass any URL — sig opens a browser, you log in normally, sig captures the session:

sig login https://jira.example.com

That's it. Check it worked:

sig status

Now use the credentials:

sig request https://jira.example.com/rest/api/2/myself

You can also pass credentials directly without opening a browser:
sig login <url> --token <pat>

Using Credentials

Four ways to use stored credentials, from most secure to least:

sig request

Make an authenticated HTTP request. Credentials never leave the process.

sig request https://jira.example.com/rest/api/2/myself # POST with body sig request https://jira.example.com/rest/api/2/issue \ --method POST \ --body '{"fields":{"summary":"Bug"}}' \ --header "Content-Type: application/json" # Output formats sig request <url> --format body # response body only sig request <url> --format headers # response headers only sig request <url> --format json # full structured response

sig run

Run any command with credentials injected as environment variables. Sensitive values are automatically redacted from output.

# Run a script with credentials sig run jira -- python fetch_issues.py # Multiple providers at once sig run jira slack -- python cross_tool.py # See what env vars are available sig run jira -- env | grep SIG_

Injected variables follow the pattern SIG_<PROVIDER>_COOKIE or SIG_<PROVIDER>_TOKEN.

sig proxy

Start a local proxy that injects credentials into any HTTP request transparently. Apps don't need any changes — just point HTTP_PROXY at it.

sig proxy start # Then any tool works automatically: export HTTP_PROXY=http://127.0.0.1:7891 export HTTPS_PROXY=http://127.0.0.1:7891 curl https://jira.example.com/rest/api/2/myself sig proxy stop

Best for long-running processes, AI agents, and tools that fork many subprocesses.

sig get

Print credential headers to stdout. Use sparingly — values are exposed in your shell.

sig get jira # JSON headers sig get jira --format value # raw cookie string sig get jira --format header # HTTP header format

Which one should I use?
sig proxy — AI agents, daemons
sig request — one-off API calls
sig run — wrapping scripts/tools
sig get — debugging only

Configuration

config.yaml

Everything lives in ~/.sig/config.yaml. Running sig login <url> auto-creates provider entries, so most users never edit this file manually.

# ~/.sig/config.yaml version: 2 mode: browser browser: execPath: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome browserDataDir: ~/.sig/browser-data storage: credentialsDir: ~/.sig/credentials providers: jira: domains: - jira.example.com entryUrl: https://jira.example.com/ strategy: browser ttl: 10d extract: - from: cookies as: session match: "*" apply: - in: header name: Cookie value: "${session}"

Adding a provider

The easiest way: just sig login <url> — sig auto-creates config. For manual setup, add a provider entry with these fields:

my-service: domains: [example.com] # which URLs this provider handles entryUrl: https://example.com/ # URL opened for login validateUrl: https://example.com/api/me # optional: protected endpoint to verify credentials strategy: browser # use browser to authenticate loginMode: auto # optional: auto (default) | headless | visible ttl: 12h # how long credentials are valid extract: - from: cookies # what to capture (cookies or localStorage) as: session # name for the captured value match: "*" # which cookies (* = all) apply: - in: header # how to inject into requests name: Cookie value: "${session}" # reference the extracted value

localStorage tokens

Some apps store tokens in localStorage instead of cookies (Slack, Microsoft Teams). Use from: localStorage with a key pattern and optional jsonPath:

app-slack: domains: [your-org.enterprise.slack.com] entryUrl: https://app.slack.com/client/YOUR_TEAM_ID strategy: browser extract: - from: cookies as: session match: "*" - from: localStorage as: xoxc-token match: localConfig_v2 jsonPath: teams.YOUR_TEAM_ID.token apply: - in: header name: Cookie value: "${session}" - in: header name: Authorization value: "Bearer ${xoxc-token}"

Public sites (validateUrl)

Public sites set tracking cookies to all visitors. Add validateUrl pointing to a protected endpoint so sig can distinguish auth cookies from anonymous ones:

reddit: domains: [www.reddit.com, reddit.com] entryUrl: https://www.reddit.com/ validateUrl: https://www.reddit.com/prefs/friends strategy: browser extract: - from: cookies as: cookie match: "*" apply: - in: header name: Cookie value: "${cookie}"

sig probes validateUrl with extracted credentials — 2xx means logged in, 401/403 means not. SSO sites don't need this — redirect detection works automatically.

Tip: Use sig login <url> --as my-name to pick a custom provider ID instead of the auto-generated one.

OAuth2 Client Credentials

For APIs that use OAuth2 Client Credentials grant — no browser needed. Configure client_id and client_secret once, sig manages token exchange, expiry tracking, and silent refresh automatically.

Quick start

sig login https://api.example.com \ --strategy oauth2 \ --token-url https://auth.example.com/oauth/token \ --client-id my-client \ --client-secret my-secret \ --scope "read write"

Or interactively — just pass --strategy oauth2 and sig prompts for the rest:

sig login https://api.example.com --strategy oauth2 # Prompts: Token URL, Client ID, Client Secret, Scopes

After setup, all commands work automatically:

sig get my-provider # Bearer token (auto-refreshes if expired) sig request https://api.example.com/data # Injects Authorization header sig run my-provider -- curl https://api.example.com/data

How it works

First login: 1. Store client_id + client_secret (encrypted at rest) 2. POST to token endpoint → receive access_token 3. Store access_token with TTL 4. Write provider config to ~/.sig/config.yaml Daily use (sig get / sig request): 1. Check stored access_token 2. If valid → inject Bearer header 3. If expired → silent re-exchange using stored secrets 4. No user interaction needed

Configuration

After first login, config.yaml stores non-sensitive settings. Secrets live in the encrypted credential store:

# ~/.sig/config.yaml (non-sensitive) my-api: domains: - api.example.com strategy: oauth2 oauth2: tokenUrl: https://auth.example.com/oauth/token scopes: - read - write apply: - in: header name: Authorization value: Bearer ${access_token}

Client ID and secret are stored only in the encrypted credential store — never in config.yaml.

Commands

# Check status sig status my-provider # Force refresh (re-exchange token) sig login my-provider --force # Update client secret sig login my-provider --client-secret new-secret # Logout (clears token, keeps secrets for next refresh) sig logout my-provider # Remove everything (config + credentials) sig remove my-provider --force

OAuth2 flags:
--strategy oauth2 — select strategy
--token-url — token endpoint
--client-id — client ID
--client-secret — client secret
--scope — space-separated scopes
--network-proxy — proxy for token requests

Remote & Sync

Log in on your laptop, push credentials to headless servers over SSH.

Setup

# On the server — set up without a browser: sig init --remote # On your laptop — add the remote and push: sig remote add prod user@server.example.com sig sync push prod # On the server — use credentials: sig run jira -- python deploy.py

Auto-refresh

Keep sessions alive automatically. The proxy daemon handles refresh in the background.

sig watch add jira # add to auto-refresh list sig proxy start # proxy also runs the refresh loop # Optional: auto-sync to remote after each refresh sig watch add jira --auto-sync prod

Troubleshooting

Run sig doctor first — it checks your browser, config, and permissions.

sig doctor
  • Login captures wrong cookies: Add validateUrl to your provider config pointing to a protected endpoint.
  • Site blocks headless browser: Use sig login <url> --mode visible or set loginMode: visible in provider config.
  • Credentials expire quickly: Set a longer ttl or use sig watch add <provider> for auto-refresh.
  • Proxy HTTPS errors: Run sig proxy trust to add the local CA to your system.
  • No browser on this machine: Use sig init --remote + sig sync pull to get credentials from another machine.

Add --verbose to any command for detailed error output.

SDKs

Lightweight read-only SDKs for consuming credentials stored by the CLI. No browser, no config — just read the encrypted credential files and use the values in your code.

npm install @sigcli/sdk # TypeScript/Node pip install sigcli-sdk # Python

TypeScript

import { SigClient, applyRules } from '@sigcli/sdk' const client = new SigClient() // Get credential (read + decrypt) const cred = await client.getCredential('my-jira') console.log(cred.values) // { cookie: "sid=abc; csrf=xyz" } // Apply template rules to get HTTP headers const { headers } = applyRules(cred.values, [ { in: 'header', name: 'Cookie', value: '${cookie}' } ]) // headers = { Cookie: "sid=abc; csrf=xyz" } // List all stored credentials const providers = await client.listProviders() // Watch for credential changes client.on('change', (providerId, credential) => { console.log(providerId, 'updated:', credential.values) }) client.watch()

Python

from sigcli_sdk import SigClient, apply_rules, ApplyRule client = SigClient() # Get credential (read + decrypt) cred = client.get_credential("my-jira") print(cred.values) # {"cookie": "sid=abc; csrf=xyz"} # Apply template rules to get HTTP headers rules = [ApplyRule(in_="header", name="Cookie", value="${cookie}")] result = apply_rules(cred.values, rules) # result.headers == {"Cookie": "sid=abc; csrf=xyz"} # Use with requests import requests response = requests.get("https://jira.example.com/rest/api/2/myself", headers=result.headers) # List all stored credentials for p in client.list_providers(): print(f"{p.providerId} ({p.strategy})")

SDK design:
The SDK reads credential files that the CLI writes to ~/.sig/credentials/. It handles AES-256-GCM decryption transparently. Use applyRules to replicate the CLI's template interpolation (${key} syntax).