# Sigcli Auth Proxy

> Secure browser SSO and OAuth2 authentication proxy that lets AI agents access authenticated APIs without exposing credentials

- Skill: `aradotso/sigcli-auth-proxy` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aradotso/sigcli-auth-proxy`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aradotso/sigcli-auth-proxy/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: aradotso (https://skillmd.com/u/aradotso)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aradotso/sigcli-auth-proxy

---


# sigcli Auth Proxy Skill

> Skill by [ara.so](https://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

```bash
npm install -g @sigcli/cli
```

Initialize configuration:

```bash
sig init  # creates ~/.sig/config.yaml
```

## Core Commands

### Authentication

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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)

```yaml
# ~/.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:

```yaml
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:

```yaml
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 code
- `res.body` - parsed JSON or raw string
- `res.headers` - response headers

### OAuth2 Client Credentials

```yaml
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:

```yaml
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):

```yaml
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:

```yaml
x:
  networkProxy: socks5://127.0.0.1:3333
  # ... rest of config
```

## Real-World Usage Patterns

### Pattern 1: Agent Accessing Jira

```typescript
// 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

```typescript
// 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

```typescript
// 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

```typescript
// 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

```bash
# 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 |
|-------------|-------------|
| Reddit      | `https://www.reddit.com/prefs/friends` |
| X (Twitter) | `https://x.com/i/api/2/notifications/all.json?count=1` |
| LinkedIn    | `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:

```yaml
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`:

```yaml
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`.

```bash
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:

```yaml
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:

```yaml
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:
1. Trust the sig CA certificate (see `sig proxy --help`)
2. Disable SSL verification in your HTTP client (development only)

### Credentials file corruption

**Symptom:** `Error reading credentials` or decryption fails.

**Solution:** Re-authenticate:

```bash
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-redaction` shows raw tokens (use carefully)

## AI Agent Integration

Agents should:
1. Run `sig status <provider>` before making requests
2. Use `sig request` for single authenticated calls
3. Use `sig proxy` for long-running sessions or multiple requests
4. Check exit codes: 0 = success, non-zero = failure
5. Parse JSON output from `sig request` directly

Example agent pattern:

```typescript
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
}
```

