
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.
@interagentic/sdk
Advanced tools
Client SDK for Interagentic — federated bot identity, authentication, and payments
Client SDK for Interagentic — agent identity, signed tokens and authenticated requests from Node.js.
Your agent gets an identity on a broker, keeps its key fresh, and proves who is calling — with a token scoped to the one server it is talking to.
npm install @interagentic/sdk
import { InteragenticClient } from '@interagentic/sdk';
const client = new InteragenticClient();
// The first call registers a namespace and stores its key in ~/.interagentic/.
// Later calls rotate the key before it goes stale.
const res = await client.fetch('https://api.github.com/user/repos', {
headers: { Authorization: 'Bearer {{OAUTH2_ACCESS_TOKEN}}' },
});
client.fetch goes through the credential proxy (https://keychains.dev by default): {{PLACEHOLDER}}s are replaced by the proxy with credentials a human connected, and never travel back to your process. For a script that needs nothing else, interagenticFetch(url, init) does the same through a shared default client.
// For a service that verifies agent tokens itself:
const token = await client.generateToken(undefined, { audience: 'api.example.com' });
await fetch('https://api.example.com/v1/orders', { headers: { Authorization: `Bearer ${token}` } });
Every token is a JWT signed by the agent's own key:
| Value | |
|---|---|
| header | { "alg": "EdDSA" | "ES256" | "RS256", "typ": "JWT", "kid": "<key id>" } |
iss | interagentic://<broker host>/<namespace> (port kept when non-default) |
sub | same as iss, or interagentic://<broker host>/org_<id> when acting for an org |
aud | the hostname of the server being called — options.audience, reduced to its hostname; the broker's hostname by default |
iat, exp | exp = iat + 300 |
jti | a random UUID, unique per token |
Mint one token per request rather than caching it. generateToken(claims, { actAs: false }) signs as the agent even while it acts for an org; extra claims are added but can never override the ones above. Every call the SDK makes to the broker uses aud = the broker's hostname.
With a stable API key (iak_… in INTERAGENTIC_STABLE_API_KEY or credentials.json), generateToken returns that key instead. Stable keys expire — 90 days from createApiKey, or whatever { expiresIn } (seconds, up to a year) asks for. Nothing renews one: read expiresAt and hand the holder a new key before it passes.
| Method | Sends | Token |
|---|---|---|
client.fetch(url, init) | through the proxy; approval, permission, link, payment and lock answers are thrown as typed errors | X-Proxy-Authorization, aud = proxy host |
client.proxyFetch(url, init, { scopes, account, stream }) | the same, but returns every response as is | X-Proxy-Authorization, aud = proxy host |
client.fetchDirect(url, init) | straight to a service that verifies agent tokens (https, or http on loopback) | Authorization, aud = target host |
Proxied requests carry the target both in the path (<proxy>/<host[:port]>/<path>) and in X-Proxy-Target-URL, so ports and http://localhost targets survive. Redirects are followed by sending the next hop through the proxy again (or, for fetchDirect, only within the same origin), so the token never reaches a host it was not minted for. A 401 stale-key answer, or a key_too_old challenge (WWW-Authenticate: Interagentic … error="key_too_old"), rotates the key and retries once.
client.supportsInteragenticAuth(url) tells whether a target publishes /.well-known/interagentic/services.json with "auth": "interagentic" (cached per origin in the state directory).
detectHumanAction(status, headers, body) classifies a response that needs a person — a 402 with its price and approval link, a 403 permission or link refusal, a 423 lock. client.waitForApproval(url) then polls until the approval is granted (client.waitForLink() for a human link).
const result = await client.executeServiceAction({
domain: 'popcorn.club', // or a short name: 'mongo' → mongo.interagentic.dev
command: ['orders', 'refunds', 'create'],
params: { id: 'ord_8fJ2', reason: 'damaged', amount: 4.5, notify: true },
jsonMode: true,
});
// POST https://popcorn.club/api/v1/orders/ord_8fJ2/refunds?notify=true
// { "reason": "damaged", "refund": { "amount": 4.5 } }
fetchServiceIndex(domain) and fetchServiceAction(domain, command) read /.well-known/interagentic/services.json and services/<segment>/…/<leaf>.json. executeServiceAction validates the arguments against the action's parameters (throwing ServiceArgumentError before any request), renders the request from its templates, signs a token with aud = the service's hostname, and returns the raw response. files: ['./dist'] uploads files under the action's files rules.
The building blocks are exported for other clients: resolveServiceCommand (the command model's greedy resolution), prepareServiceArguments, renderServiceRequest (request templates, §4 of the spec) and collectServiceFiles.
Keys rotate automatically before they go stale; client.keys.rotate() rotates on demand. Rotation follows the broker contract and is safe to run concurrently:
rotation.lock in the state directory (a rotation another process finished while this one waited is returned instead of chaining a second one);private.pem.pending before the broker is called;identity.json together with the promoted key; 409 (the key is already current) counts as success;429 is retried with backoff.If the process dies mid-rotation, the next run tries the pending key first, looks for it in the namespace's published key set, and otherwise replays the rotation idempotently. It never signs an ordinary request with a key that may have been rotated out — that is what makes a broker lock the namespace.
| Option | Environment variable | Default |
|---|---|---|
serverUrl | INTERAGENTIC_BROKER (or INTERAGENTIC_SERVER_URL) | https://id.interagentic.dev |
stateDir | INTERAGENTIC_STATE_DIR | ~/.interagentic |
proxyUrl | INTERAGENTIC_PROXY_URL | https://keychains.dev |
algorithm | — | EdDSA (ES256, RS256) |
rotationTTL | — | 15 minutes |
inviteToken | INTERAGENTIC_INVITE_TOKEN | — |
INTERAGENTIC_ACT_AS makes tokens act for an org; INTERAGENTIC_STABLE_API_KEY switches to a stable API key.
~/.interagentic/ (0700)
├── identity.json broker, namespace, key id, algorithm, rotation time (0600)
├── private.pem the private key (0600)
├── private.pem.pending write-ahead log of an in-flight rotation (0600)
└── rotation.lock held while rotating
| Class | Code | HTTP | When |
|---|---|---|---|
InteragenticError | varies | varies | Base class: code, message, statusCode, actionUrl |
NamespaceLockedError | NAMESPACE_LOCKED | 423 | A human must unlock the namespace |
PaymentRequiredError | PAYMENT_REQUIRED | 402 | credits (decimal string), description, actionUrl |
InsufficientPermissionError | INSUFFICIENT_PERMISSION | 403 | A permission or scope is missing; missingScopes |
LinkRequiredError | LINK_REQUIRED | 403 | A human has to link the agent or approve a credential |
ServiceArgumentError | INVALID_ARGUMENTS | — | Service arguments failed validation; problems |
Network failures are reported as InteragenticError with code NETWORK_ERROR.
npm test
The tests run against local mock servers only (a broker that implements the rotation contract, a proxy and a Services v1 service); a network guard fails any request to a non-local host.
MIT
FAQs
Client SDK for Interagentic — federated bot identity, authentication, and payments
The npm package @interagentic/sdk receives a total of 0 weekly downloads. As such, @interagentic/sdk popularity was classified as not popular.
We found that @interagentic/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.