sigcli Auth Proxy Skill
Skill by ara.so — Devtools Skills collection.
Overview
sigcli is an authentication CLI and proxy that handles browser-based SSO, OAuth2 flows, and credential injection for AI agents. It extracts credentials (cookies, localStorage, OAuth tokens), encrypts them locally with AES-256-GCM, and injects them into HTTP requests — so agents can access authenticated APIs without ever seeing secrets.
Key capabilities:
- Browser SSO authentication for any website/SSO provider
- OAuth2 Client Credentials flow with automatic token refresh
- Encrypted credential storage (
~/.sig/credentials/) - Transparent HTTP proxy for agents (
sig proxy) - Direct authenticated requests (
sig request) - Command execution with injected credentials (
sig run) - Multi-provider support in single commands
Installation
npm install -g @sigcli/cli
Initialize configuration:
sig init # creates ~/.sig/config.yaml
Core Commands
Authentication
# Browser-based SSO (auto-provision)
sig login https://jira.example.com
# OAuth2 Client Credentials
sig login https://api.example.com \
--strategy oauth2 \
--token-url https://api.example.com/oauth/token \
--client-id $CLIENT_ID \
--client-secret $CLIENT_SECRET
# Check authentication status
sig status # all providers
sig status jira-example # specific provider
# View credentials (redacted by default)
sig get jira-example # shows redacted credentials
sig get jira-example --no-redaction # shows raw tokens
# Logout (clears credentials, keeps config)
sig logout jira-example
Making Authenticated Requests
# Direct HTTP request
sig request https://jira.example.com/rest/api/2/myself
# POST with JSON body
sig request https://jira.example.com/rest/api/2/search \
--method POST \
--body '{"jql":"assignee=currentUser()"}'
# Multiple providers in one request
sig request https://api.example.com/data \
--provider jira-example,github-enterprise
Running Commands with Auth
# Execute command with credentials injected
sig run jira-example -- curl https://jira.example.com/rest/api/2/myself
# Multi-provider execution
sig run github-enterprise,jira-example -- node script.js
# Environment variables are automatically injected based on apply[] rules
HTTP Proxy Mode
# Start MITM proxy (injects credentials transparently)
sig proxy --port 8080
# In another terminal or agent config:
export HTTP_PROXY=http://localhost:8080
export HTTPS_PROXY=http://localhost:8080
curl https://jira.example.com/rest/api/2/myself
# Credentials auto-injected by sig proxy
Configuration
Configuration lives in ~/.sig/config.yaml. Providers are auto-provisioned for SSO sites, or manually configured for public sites and OAuth2.
Auto-Provisioned SSO (Zero Config)
# ~/.sig/config.yaml (generated by sig login)
jira-example:
domains:
- jira.example.com
entryUrl: https://jira.example.com/
strategy: browser
extract:
- from: cookies
as: session
match: '*'
apply:
- in: header
name: Cookie
value: '${session}'
Public Sites with Validation
Public sites need validateUrl and/or validateRule to distinguish auth cookies from tracking cookies:
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}'
Validation Rule (JavaScript Expression)
For APIs that return 200 even when unauthenticated:
douyin:
domains:
- www.douyin.com
entryUrl: https://www.douyin.com
validateUrl: https://www.douyin.com/aweme/v1/web/notice/count/
validateRule: 'res.body.status_code === 0'
strategy: browser
extract:
- from: cookies
as: cookie
match: '*'
apply:
- in: header
name: Cookie
value: '${cookie}'
validateRule context:
res.status- HTTP status coderes.body- parsed JSON or raw stringres.headers- response headers
OAuth2 Client Credentials
api-example:
domains:
- api.example.com
strategy: oauth2
tokenUrl: https://api.example.com/oauth/token
clientId: ${CLIENT_ID}
clientSecret: ${CLIENT_SECRET}
scopes:
- read:data
- write:data
extract:
- from: oauth2
as: access_token
apply:
- in: header
name: Authorization
value: 'Bearer ${access_token}'
localStorage Extraction
For apps that store tokens in localStorage:
app-slack:
domains:
- your-org.enterprise.slack.com
entryUrl: https://app.slack.com/client/T12345
strategy: browser
extract:
- from: cookies
as: session
match: '*'
- from: localStorage
as: xoxc-token
match: localConfig_v2
jsonPath: teams.T12345.token
apply:
- in: header
name: Cookie
value: '${session}'
- in: header
name: Authorization
value: 'Bearer ${xoxc-token}'
Multi-Domain Providers
For sites that use multiple domains (e.g., twitter.com → x.com migration):
x:
domains:
- x.com
- twitter.com
entryUrl: https://x.com/
validateUrl: https://x.com/i/api/2/notifications/all.json?count=1
strategy: browser
extract:
- from: cookies
as: cookie
match: '*'
- from: cookies
as: ct0
match: 'ct0'
apply:
- in: header
name: Cookie
value: '${cookie}'
- in: header
name: x-csrf-token
value: '${ct0}'
Network Proxy (for VPN/SOCKS)
If the browser needs to go through a proxy:
x:
networkProxy: socks5://127.0.0.1:3333
# ... rest of config
Real-World Usage Patterns
Pattern 1: Agent Accessing Jira
// agent-jira.ts
import { execSync } from 'child_process';
function getJiraIssue(issueKey: string): object {
const url = `https://jira.example.com/rest/api/2/issue/${issueKey}`;
const result = execSync(`sig request ${url}`, { encoding: 'utf8' });
return JSON.parse(result);
}
function searchJiraIssues(jql: string): object {
const url = 'https://jira.example.com/rest/api/2/search';
const body = JSON.stringify({ jql });
const result = execSync(
`sig request ${url} --method POST --body '${body}'`,
{ encoding: 'utf8' }
);
return JSON.parse(result);
}
// Usage
const issue = getJiraIssue('PROJ-123');
const myIssues = searchJiraIssues('assignee=currentUser()');
Pattern 2: OAuth2 API with Auto-Refresh
// oauth-api-client.ts
import { execSync } from 'child_process';
class AuthenticatedAPIClient {
constructor(private provider: string) {}
private exec(cmd: string): string {
return execSync(cmd, { encoding: 'utf8' });
}
async makeRequest(endpoint: string, method = 'GET', body?: object): Promise<any> {
let cmd = `sig request https://api.example.com${endpoint} --method ${method}`;
if (body) {
cmd += ` --body '${JSON.stringify(body)}'`;
}
try {
const result = this.exec(cmd);
return JSON.parse(result);
} catch (error) {
// sig automatically refreshes OAuth2 tokens on 401
throw error;
}
}
checkStatus(): void {
const status = this.exec(`sig status ${this.provider}`);
console.log(status);
}
}
// Usage
const client = new AuthenticatedAPIClient('oauth-mock');
const data = await client.makeRequest('/api/data');
Pattern 3: Proxy Mode for HTTP Client
// proxy-mode-agent.ts
import axios from 'axios';
import { spawn } from 'child_process';
// Start sig proxy
const proxy = spawn('sig', ['proxy', '--port', '8080'], {
stdio: 'inherit'
});
// Configure axios to use proxy
const client = axios.create({
proxy: {
host: 'localhost',
port: 8080,
},
});
// All requests auto-authenticated
async function fetchData() {
const response = await client.get('https://jira.example.com/rest/api/2/myself');
return response.data;
}
// Cleanup
process.on('exit', () => proxy.kill());
Pattern 4: Multi-Provider Request
// multi-provider-sync.ts
import { execSync } from 'child_process';
function syncDataAcrossSystems(): void {
// Single request with credentials from multiple providers
const result = execSync(
`sig request https://api.example.com/sync \
--provider jira-example,github-enterprise \
--method POST \
--body '{"sync": true}'`,
{ encoding: 'utf8' }
);
console.log('Sync result:', JSON.parse(result));
}
Pattern 5: Running External Tools
# Use sig run to inject credentials into any command
# cURL
sig run jira-example -- curl https://jira.example.com/rest/api/2/myself
# Python script
sig run github-enterprise -- python sync_repos.py
# Node.js script with multiple providers
sig run jira-example,slack-enterprise -- node agent.js
Common Validation URLs
| Service | validateUrl |
|---|---|
https://www.reddit.com/prefs/friends |
|
| X (Twitter) | https://x.com/i/api/2/notifications/all.json?count=1 |
https://www.linkedin.com/voyager/api/me |
|
| YouTube | https://www.youtube.com/account |
| V2EX | https://www.v2ex.com/notifications |
| Zhihu | https://www.zhihu.com/api/v4/me |
Troubleshooting
Provider auto-provision fails
Symptom: sig login completes but provider not created.
Solution: Add validateUrl for public sites:
reddit:
validateUrl: https://www.reddit.com/prefs/friends
Credentials extracted but validation fails
Symptom: Browser login succeeds but sig reports "not authenticated".
Solution 1: Check if API returns 200 with error in body. Add validateRule:
validateRule: 'res.body.status_code === 0'
Solution 2: Ensure validateUrl is a protected endpoint (returns 401/403 when logged out).
OAuth2 token not refreshing
Symptom: Token expires and requests fail.
Solution: Verify tokenUrl, clientId, clientSecret in config. Check that the OAuth2 server supports grant_type=client_credentials.
sig logout oauth-provider # clear old token
sig get oauth-provider # force re-authentication
localStorage extraction returns null
Symptom: from: localStorage extracts nothing.
Solution: Check jsonPath syntax. Open browser DevTools → Application → Local Storage and verify the key structure:
extract:
- from: localStorage
as: token
match: appConfig # localStorage key
jsonPath: user.auth.token # nested path
Proxy mode not injecting credentials
Symptom: HTTP_PROXY set but requests are unauthenticated.
Solution: Ensure domains match. The proxy only injects credentials for domains listed in provider config:
provider-name:
domains:
- api.example.com
- auth.example.com # add all relevant domains
Certificate errors in proxy mode
Symptom: SSL certificate verification fails.
Solution: sig proxy uses MITM. Either:
- Trust the sig CA certificate (see
sig proxy --help) - Disable SSL verification in your HTTP client (development only)
Credentials file corruption
Symptom: Error reading credentials or decryption fails.
Solution: Re-authenticate:
rm ~/.sig/credentials/provider-name.json
sig login https://provider.example.com
Security Notes
- Credentials encrypted with AES-256-GCM
- Stored in
~/.sig/credentials/(mode 600) - Audit log in
~/.sig/logs/ - Never pass credentials through environment variables or shell history
sig get --no-redactionshows raw tokens (use carefully)
AI Agent Integration
Agents should:
- Run
sig status <provider>before making requests - Use
sig requestfor single authenticated calls - Use
sig proxyfor long-running sessions or multiple requests - Check exit codes: 0 = success, non-zero = failure
- Parse JSON output from
sig requestdirectly
Example agent pattern:
function ensureAuthenticated(provider: string): boolean {
try {
execSync(`sig status ${provider}`, { encoding: 'utf8' });
return true;
} catch {
console.error(`Not authenticated. Run: sig login https://${provider}.com`);
return false;
}
}
if (ensureAuthenticated('jira-example')) {
const data = execSync('sig request https://jira.example.com/rest/api/2/myself');
// process data
}