sigcli-auth-proxy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

sigcli Auth Proxy Skill

sigcli 认证代理 Skill

Skill by ara.so — Devtools Skills collection.
Skill 由 ara.so 提供 —— Devtools Skills 集合。

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
sigcli 是一款认证CLI和代理工具,可为AI Agent处理基于浏览器的SSO、OAuth2流程以及凭证注入。它提取凭证(Cookie、localStorage、OAuth令牌),使用AES-256-GCM在本地加密,并将其注入HTTP请求——这样Agent就可以访问需认证的API,且全程不会接触到机密信息。
核心功能:
  • 支持任意网站/SSO提供商的浏览器SSO认证
  • 带自动令牌刷新的OAuth2客户端凭证流程
  • 加密凭证存储(
    ~/.sig/credentials/
  • 面向Agent的透明HTTP代理(
    sig proxy
  • 直接发送认证请求(
    sig request
  • 注入凭证执行命令(
    sig run
  • 单命令支持多提供商

Installation

安装

bash
npm install -g @sigcli/cli
Initialize configuration:
bash
sig init  # creates ~/.sig/config.yaml
bash
npm install -g @sigcli/cli
初始化配置:
bash
sig init  # 创建 ~/.sig/config.yaml

Core Commands

核心命令

Authentication

认证

bash
undefined
bash
undefined

Browser-based SSO (auto-provision)

基于浏览器的SSO(自动配置)

OAuth2 Client Credentials

OAuth2客户端凭证

sig login https://api.example.com
--strategy oauth2
--token-url https://api.example.com/oauth/token
--client-id $CLIENT_ID
--client-secret $CLIENT_SECRET
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
sig status # 所有提供商 sig status jira-example # 指定提供商

View credentials (redacted by default)

查看凭证(默认脱敏)

sig get jira-example # shows redacted credentials sig get jira-example --no-redaction # shows raw tokens
sig get jira-example # 显示脱敏凭证 sig get jira-example --no-redaction # 显示原始令牌

Logout (clears credentials, keeps config)

登出(清除凭证,保留配置)

sig logout jira-example
undefined
sig logout jira-example
undefined

Making Authenticated Requests

发送认证请求

bash
undefined
bash
undefined

Direct HTTP request

直接发送HTTP请求

POST with JSON body

带JSON体的POST请求

sig request https://jira.example.com/rest/api/2/search
--method POST
--body '{"jql":"assignee=currentUser()"}'
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
undefined
sig request https://api.example.com/data
--provider jira-example,github-enterprise
undefined

Running Commands with Auth

带认证信息执行命令

bash
undefined
bash
undefined

Execute command with credentials injected

注入凭证执行命令

sig run jira-example -- curl https://jira.example.com/rest/api/2/myself
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
sig run github-enterprise,jira-example -- node script.js

Environment variables are automatically injected based on apply[] rules

会根据apply[]规则自动注入环境变量

undefined
undefined

HTTP Proxy Mode

HTTP代理模式

bash
undefined
bash
undefined

Start MITM proxy (injects credentials transparently)

启动MITM代理(自动注入凭证)

sig proxy --port 8080
sig proxy --port 8080

In another terminal or agent config:

在另一个终端或Agent配置中:

Credentials auto-injected by sig proxy

凭证由sig proxy自动注入

undefined
undefined

Configuration

配置

Configuration lives in
~/.sig/config.yaml
. Providers are auto-provisioned for SSO sites, or manually configured for public sites and OAuth2.
配置文件位于
~/.sig/config.yaml
。SSO站点会自动配置提供商,公共站点和OAuth2需手动配置。

Auto-Provisioned SSO (Zero Config)

自动配置SSO(零配置)

yaml
undefined
yaml
undefined

~/.sig/config.yaml (generated by sig login)

~/.sig/config.yaml(由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}'
undefined
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}'
undefined

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}'
公共站点需要
validateUrl
和/或
validateRule
来区分认证Cookie和跟踪Cookie:
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)

验证规则(JavaScript表达式)

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
针对未认证时仍返回200的API:
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上下文:
  • res.status
    - HTTP状态码
  • res.body
    - 解析后的JSON或原始字符串
  • res.headers
    - 响应头

OAuth2 Client Credentials

OAuth2客户端凭证

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}'
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

localStorage提取

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}'
针对将令牌存储在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}'
针对使用多个域名的站点(例如twitter.com → x.com迁移):
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)

网络代理(适用于VPN/SOCKS)

If the browser needs to go through a proxy:
yaml
x:
  networkProxy: socks5://127.0.0.1:3333
  # ... rest of config
如果浏览器需要通过代理访问:
yaml
x:
  networkProxy: socks5://127.0.0.1:3333
  # ... 其余配置

Real-World Usage Patterns

实际使用场景

Pattern 1: Agent Accessing Jira

场景1:Agent访问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()');
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);
}

// 使用示例
const issue = getJiraIssue('PROJ-123');
const myIssues = searchJiraIssues('assignee=currentUser()');

Pattern 2: OAuth2 API with Auto-Refresh

场景2:带自动刷新的OAuth2 API

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');
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) {
      // 遇到401时,sig会自动刷新OAuth2令牌
      throw error;
    }
  }

  checkStatus(): void {
    const status = this.exec(`sig status ${this.provider}`);
    console.log(status);
  }
}

// 使用示例
const client = new AuthenticatedAPIClient('oauth-mock');
const data = await client.makeRequest('/api/data');

Pattern 3: Proxy Mode for HTTP Client

场景3:HTTP客户端代理模式

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());
typescript
// proxy-mode-agent.ts
import axios from 'axios';
import { spawn } from 'child_process';

// 启动sig代理
const proxy = spawn('sig', ['proxy', '--port', '8080'], {
  stdio: 'inherit'
});

// 配置axios使用代理
const client = axios.create({
  proxy: {
    host: 'localhost',
    port: 8080,
  },
});

// 所有请求自动认证
async function fetchData() {
  const response = await client.get('https://jira.example.com/rest/api/2/myself');
  return response.data;
}

// 清理进程
process.on('exit', () => proxy.kill());

Pattern 4: Multi-Provider Request

场景4:多提供商请求

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));
}
typescript
// multi-provider-sync.ts
import { execSync } from 'child_process';

function syncDataAcrossSystems(): void {
  // 单请求使用多提供商凭证
  const result = execSync(
    `sig request https://api.example.com/sync \
      --provider jira-example,github-enterprise \
      --method POST \
      --body '{"sync": true}'`,
    { encoding: 'utf8' }
  );
  
  console.log('同步结果:', JSON.parse(result));
}

Pattern 5: Running External Tools

场景5:运行外部工具

bash
undefined
bash
undefined

Use sig run to inject credentials into any command

使用sig run将凭证注入任意命令

cURL

cURL

sig run jira-example -- curl https://jira.example.com/rest/api/2/myself
sig run jira-example -- curl https://jira.example.com/rest/api/2/myself

Python script

Python脚本

sig run github-enterprise -- python sync_repos.py
sig run github-enterprise -- python sync_repos.py

Node.js script with multiple providers

带多提供商凭证的Node.js脚本

sig run jira-example,slack-enterprise -- node agent.js
undefined
sig run jira-example,slack-enterprise -- node agent.js
undefined

Common Validation URLs

常用验证URL

ServicevalidateUrl
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
服务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
知乎
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
症状:
sig login
执行完成但未创建提供商。
解决方案: 为公共站点添加
validateUrl
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).
症状: 浏览器登录成功但sig提示“未认证”。
解决方案1: 检查API是否返回200但响应体包含错误信息。添加
validateRule
yaml
validateRule: 'res.body.status_code === 0'
解决方案2: 确保
validateUrl
是受保护的端点(未登录时返回401/403)。

OAuth2 token not refreshing

OAuth2令牌未自动刷新

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
症状: 令牌过期后请求失败。
解决方案: 验证配置中的
tokenUrl
clientId
clientSecret
。确认OAuth2服务器支持
grant_type=client_credentials
bash
sig logout oauth-provider  # 清除旧令牌
sig get oauth-provider     # 强制重新认证

localStorage extraction returns null

localStorage提取返回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
症状:
from: localStorage
未提取到任何内容。
解决方案: 检查
jsonPath
语法。打开浏览器开发者工具→Application→Local Storage,验证键结构:
yaml
extract:
  - from: localStorage
    as: token
    match: appConfig           # localStorage键名
    jsonPath: user.auth.token  # 嵌套路径

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
症状: 已设置HTTP_PROXY但请求未认证。
解决方案: 确保域名匹配。代理仅会为提供商配置中列出的域名注入凭证:
yaml
provider-name:
  domains:
    - api.example.com
    - auth.example.com  # 添加所有相关域名

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)
症状: SSL证书验证失败。
解决方案: sig proxy使用MITM技术。可选择:
  1. 信任sig CA证书(查看
    sig proxy --help
  2. 在HTTP客户端中禁用SSL验证(仅开发环境)

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
症状: 出现
Error reading credentials
或解密失败。
解决方案: 重新认证:
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)
  • 凭证使用AES-256-GCM加密
  • 存储在
    ~/.sig/credentials/
    (权限600)
  • 审计日志位于
    ~/.sig/logs/
  • 切勿通过环境变量或Shell历史传递凭证
  • sig get --no-redaction
    会显示原始令牌(谨慎使用)

AI Agent Integration

AI Agent集成

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
}
Agent应遵循以下步骤:
  1. 发送请求前运行
    sig status <provider>
    检查认证状态
  2. 使用
    sig request
    发送单次认证请求
  3. 对于长期会话或多次请求,使用
    sig proxy
  4. 检查退出码:0=成功,非0=失败
  5. 直接解析
    sig request
    返回的JSON输出
示例Agent模式:
typescript
function ensureAuthenticated(provider: string): boolean {
  try {
    execSync(`sig status ${provider}`, { encoding: 'utf8' });
    return true;
  } catch {
    console.error(`未认证。请执行:sig login https://${provider}.com`);
    return false;
  }
}

if (ensureAuthenticated('jira-example')) {
  const data = execSync('sig request https://jira.example.com/rest/api/2/myself');
  // 处理数据
}