
Security News
Lovable’s OJ Rewrites Vite’s Dev Server in Rust as AI Lowers the Cost of Forking Open Source
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.
@keychains/server-sdk
Advanced tools
Server SDK for Keychains.dev (BETA) — register trusted apps, create permissions, mint tokens, and make proxy calls via JWKS authentication
BETA — This SDK is under active development. APIs may change.
Server SDK for Keychains.dev — give your server-side app secure access to user credentials (OAuth tokens, API keys) through the Keychains proxy.
npm install @keychains/server-sdk
npx @keychains/server-sdk register myapp.com
The register script will:
jwks.json to the right location for your projectKEYCHAINS_* env vars to your .envimport { KeychainsApp } from '@keychains/server-sdk';
const keychains = KeychainsApp.fromEnv();
Everything is transparent until the proxy request — identical to how keychains curl works. A wildcard permission is created automatically, and the auth URL only surfaces when the user actually needs to connect a service.
// One-liner — fetch through the proxy:
try {
const res = await keychains.forUser(userId).withTask('Project Albatros').fetch('https://api.github.com/user');
const data = await res.json();
} catch (err) {
if (err instanceof KeychainsAppError && err.approvalUrl) {
// User hasn't connected GitHub yet — show them this URL
console.log(`Please authorize: ${err.approvalUrl}`);
}
}
Or step by step:
// Get a token (creates a wildcard permission if needed)
const { token } = await keychains.forUser(userId).withTask('Project Albatros').getToken();
// Use the token for one or more proxy requests
const res = await keychains.fetch('https://api.github.com/user', { permissionToken: token });
When to use: Quick prototyping, AI agents, cases where you don't know upfront which services the user will need.
Create a scoped permission with specific scopes. The user approves upfront, then all subsequent requests go through without interruption.
const scopes = ['gmail.com::oauth2::read', 'linear.app::oauth2::read'];
const permission = await keychains.forUser(userId).withTask('Project Albatros').getPermission(scopes);
// Show approval URL to the user
console.log('Please approve at: ' + permission.approvalUrl());
// Check if approved (poll or after redirect)
if (await permission.isApproved()) {
const res = await permission.fetch('https://gmail.googleapis.com/gmail/v1/users/me/messages');
// or: const { token } = await permission.getToken();
}
When to use: Apps with explicit user consent UIs, when you know exactly which services are needed.
KeychainsApp// From environment variables (recommended)
const keychains = KeychainsApp.fromEnv();
// Manual configuration
const keychains = new KeychainsApp({
domain: 'myapp.com',
privateKey: process.env.KEYCHAINS_PRIVATE_KEY!,
keyId: 'key-1',
serverUrl: 'https://keychains.dev', // optional
});
keychains.setAppId(process.env.KEYCHAINS_APP_ID!);
| Method | Returns | Description |
|---|---|---|
.forUser(userId) | UserContext | Scope operations to a user |
.forUser(id).withTask(name) | TaskContext | Scope to a user + task |
.forUser(id).withTask(name).fetch(url, opts?) | Response | Wildcard token + proxied fetch |
.forUser(id).withTask(name).getToken() | TokenResult | Wildcard token for manual fetch |
.forUser(id).withTask(name).getPermission(scopes?) | Permission | Scoped permission for pre-approval |
.forUser(id).getTokenForTask(name) | TokenResult | Shortcut for .withTask(name).getToken() |
.forUser(id).getPermissionForTask(name, scopes) | Permission | Shortcut for .withTask(name).getPermission(scopes) |
| Method | Description |
|---|---|
.createPermission(opts) | Create a permission request |
.listPermissions(appUserId) | List permissions for a user |
.getPermissionStatus(id, appUserId) | Check permission status |
.mintToken(permissionId, appUserId, ttl?) | Mint a short-lived token |
.fetch(url, { permissionToken }) | Proxied fetch with a token |
.register({ verify? }) | DNS registration flow |
.delegate(permissionId, appUserId, opts) | Delegate access to VMs |
Permission| Method | Returns | Description |
|---|---|---|
.approvalUrl() | string | undefined | URL for user to approve |
.isApproved() | boolean | Poll if permission is active |
.getToken(ttl?) | TokenResult | Mint a token |
.fetch(url, opts?) | Response | Mint token + proxied fetch |
import { KeychainsAppError } from '@keychains/server-sdk';
try {
const res = await keychains.forUser(userId).withTask('My Task').fetch(url);
} catch (err) {
if (err instanceof KeychainsAppError) {
if (err.approvalUrl) {
// User needs to authorize — redirect or show the URL
console.log(`Authorize: ${err.approvalUrl}`);
} else {
console.error(`${err.code}: ${err.message}`);
}
}
}
| Code | Description |
|---|---|
authorization_required | Proxy request needs user approval (has approvalUrl) |
missing_env | Required environment variables not set |
not_registered | App ID not set — run register or call setAppId() |
unauthorized | Invalid or expired JWT |
not_found | Permission or app not found |
forbidden | Permission revoked or app revoked |
npx @keychains/server-sdk register myapp.com
This generates a keypair, writes jwks.json, and walks you through DNS verification.
Your domain must serve the JWKS file at:
https://myapp.com/.well-known/keychains.dev/jwks.json
For Next.js / static sites, the register script places it in public/ by default.
Add a TXT record as instructed by the script. Once verified, your app is registered and the env vars are written to .env.
Delegate access to VMs or sub-agents:
const delegate = await keychains.delegate(permissionId, userId, {
publicKey: vmPublicKey,
scopes: ['github.com::oauth2::repo'],
});
// Or use bootstrap token for self-registration
const delegate = await keychains.delegate(permissionId, userId, {
useBootstrapToken: true,
scopes: ['github.com::oauth2::repo'],
});
// delegate.bootstrapToken → send to VM
| Variable | Required | Description |
|---|---|---|
KEYCHAINS_DOMAIN | Yes | Your registered domain |
KEYCHAINS_PRIVATE_KEY | Yes | PEM-encoded private key |
KEYCHAINS_KEY_ID | Yes | Key ID (kid) from your JWKS |
KEYCHAINS_APP_ID | No | App ID (auto-set by register script) |
KEYCHAINS_SERVER_URL | No | Override server URL (default: https://keychains.dev) |
Proprietary — Interagentic Inc.
FAQs
Server SDK for Keychains.dev (BETA) — register trusted apps, create permissions, mint tokens, and make proxy calls via JWKS authentication
The npm package @keychains/server-sdk receives a total of 1 weekly downloads. As such, @keychains/server-sdk popularity was classified as not popular.
We found that @keychains/server-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Lovable’s OJ rewrites Vite’s dev server in Rust, reducing memory use and preview times as AI lowers the cost of open source reimplementation.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.