New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

@keychains/client-sdk

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@keychains/client-sdk

Client SDK for Keychains.dev — make authenticated API calls through the Keychains proxy

latest
npmnpm
Version
0.0.9
Version published
Maintainers
1
Created
Source

@keychains/client-sdk

Minimal, zero-dependency SDK for making authenticated API calls through the Keychains.dev proxy. Your code never touches real credentials — the proxy injects them at runtime.

Quickstart

1. Install

npm install @keychains/client-sdk

2. Run with a fresh token

The keychains token command registers your machine (if needed), creates a wildcard permission, and mints a short-lived proxy token — all in one step:

KEYCHAINS_TOKEN=$(npx -y keychains token) \
  node your_script.js

3. Write your script

Use keychainsFetch as a drop-in replacement for fetch. The only difference? You can replace any credential with a template variable:

import { keychainsFetch } from '@keychains/client-sdk';

// Gmail — get last 10 emails from my inbox
const res = await keychainsFetch(
  'https://gmail.googleapis.com/gmail/v1/users/me/messages?maxResults=10',
  {
    headers: {
      Authorization: 'Bearer {{OAUTH2_ACCESS_TOKEN}}',
    },
  },
);

const emails = await res.json();
console.log(emails);

That's it. The proxy resolves {{OAUTH2_ACCESS_TOKEN}} with the user's real Google OAuth token — your code never sees it.

Running multiple scripts

Tokens expire after 15 minutes. To reuse the same token across multiple commands in a shell session, use eval:

eval $(npx -y keychains token --env)
# KEYCHAINS_TOKEN is now set for the next 15 minutes
node script_a.js
node script_b.js

Template Variables

How to write them

Template variables use the {{VARIABLE_NAME}} syntax. The variable name tells the proxy which type of credential to inject:

PrefixTypeSupported Variables
OAUTH2_OAuth 2.0 token{{OAUTH2_ACCESS_TOKEN}}, {{OAUTH2_REFRESH_TOKEN}}
OAUTH1_OAuth 1.0 token{{OAUTH1_ACCESS_TOKEN}}, {{OAUTH1_REQUEST_TOKEN}}
Anything elseAPI key{{LIFX_PERSONAL_ACCESS_TOKEN}}, {{OPENAI_API_KEY}}, etc.

Where to put them

Place them exactly where you'd normally put the real credential — headers, body, or query parameters:

// In a header (most common)
await keychainsFetch('https://api.lifx.com/v1/lights/all', {
  headers: { Authorization: 'Bearer {{LIFX_PERSONAL_ACCESS_TOKEN}}' },
});

// In the request body
await keychainsFetch('https://slack.com/api/chat.postMessage', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer {{OAUTH2_ACCESS_TOKEN}}',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ channel: '#general', text: 'Hello!' }),
});

// In query parameters
await keychainsFetch(
  'https://api.example.com/data?api_key={{MY_API_KEY}}&format=json',
);

// Multi-account: target a specific account by identifier
await keychainsFetch('https://api.github.com/user', {
  headers: { Authorization: 'Bearer {{OAUTH2_ACCESS_TOKEN}}' },
  account: 'work@company.com',
});

What Happens Next

When you call keychainsFetch:

  • URL rewritinghttps://api.lifx.com/v1/lights/all becomes https://keychains.dev/api.lifx.com/v1/lights/all
  • Token injection — your permission token is sent via X-Proxy-Authorization so the proxy knows who you are
  • Scope check — the proxy verifies the user has approved the required credentials for this API
  • Credential resolution — the proxy replaces {{LIFX_PERSONAL_ACCESS_TOKEN}} with the real API key stored in the user's vault
  • Request forwarding — the proxy forwards the request to the upstream API with real credentials injected
  • Response passthrough — the upstream response is returned to you as-is

Handling missing approvals

With wildcard permissions, users approve scopes on demand. The first time your code hits a new API, the user may not have approved it yet. When that happens, keychainsFetch throws an InsufficientScopeError containing an approvalUrl — share it with the user so they can grant access:

import { keychainsFetch, InsufficientScopeError } from '@keychains/client-sdk';

try {
  const res = await keychainsFetch('https://api.github.com/user', {
    headers: { Authorization: 'Bearer {{OAUTH2_ACCESS_TOKEN}}' },
  });
  console.log(await res.json());
} catch (err) {
  if (err instanceof InsufficientScopeError) {
    // The user hasn't approved GitHub yet — show them the link
    console.log('Please approve access:', err.approvalUrl);
    // Once approved, retry the same call and it will succeed
  }
}

The error includes useful details:

PropertyTypeDescription
approvalUrlstring?URL the user should visit to approve the missing scopes
missingScopesstring[]?Scopes that need approval
refusedScopesstring[]?Scopes explicitly refused by the user
codestringError code (insufficient_scope, scope_refused, permission_denied, etc.)

Security benefits

  • Secrets never leave the Keychains.dev servers — your code, logs, and environment stay clean
  • Users approve exactly which scopes and APIs an agent can access
  • Credentials can only be sent to the APIs of the providers they belong to
  • Every proxied request is audited with full traceability
  • Permissions can be revoked instantly from the dashboard

Other SDKs

We also offer @keychains/machine-sdk for standalone machines and long-running agents. It handles machine registration, permission creation, token minting, and delegation — all from Node.js, without the CLI.

Bug Reports & Feedback

Found a bug or have a suggestion? Submit it straight from your terminal:

# Report a bug
npx -y keychains feedback "The proxy returns 502 on large POST bodies"

# Send feedback
npx -y keychains feedback --type feedback "Love the wildcard permissions!"

# With more detail
npx -y keychains feedback --type bug \
  --title "502 on large POST" \
  --description "When sending >1MB body to Slack API..." \
  --contact you@example.com

The keychains feedback command (alias: keychains bug) sends your report directly to the engineering team.

More Info

Let's meet on keychains.dev!

Keywords

keychains

FAQs

Package last updated on 13 Mar 2026

Related posts