@alter-ai/alter-sdk
v0.20.0
Published
Official TypeScript SDK for Alter Vault — OAuth token management with policy enforcement
Readme
Alter SDK for TypeScript / Node.js
Official TypeScript SDK for Alter Vault — credential and authorization layer for apps and AI agents that call third-party APIs.
Tokens stay in the vault. The SDK injects the credential, refreshes it, and writes the audit row — application code only calls vault.request() (or vault.proxyRequest() when the backend should make the outgoing call instead of the SDK).
Install
npm install @alter-ai/alter-sdkRuns on Node.js 20+ and is intended for server-side environments. For browser-side OAuth popup flows, see @alter-ai/connect.
Quick example
Make an authenticated API call — no token ever touches application code.
import { App, HttpMethod } from "@alter-ai/alter-sdk";
const vault = new App({ apiKey: "<api-key>" });
try {
const response = await vault.request(
HttpMethod.POST,
"https://api.example.com/resource",
{
grantId: "<grant-id>",
json: { example: "payload" },
},
);
console.log(response.status, await response.json());
} finally {
await vault.close();
}For a full walkthrough — sign-up, key minting, OAuth — see the Quickstart.
Two runtime modes
The SDK exposes two ways to reach a third-party API:
vault.request(...)— retrieve mode. The SDK fetches the token from the backend and makes the outgoing call itself. Returns the third-party response.vault.proxyRequest(...)— proxy mode. The backend holds the token, makes the outgoing call, and returns the result. Application code and the SDK never observe the token. Required for any grant configured with human-in-the-loop approval; available for any other grant when wire-level audit, strong token isolation, or backend-side policy enforcement matter.
See runtime modes for the tradeoffs and when to pick each.
Recovering from missing-grant errors
When a request fails because the user hasn't authorized the provider yet, the SDK exposes recovery context on the typed error so you can drive a re-consent flow without re-deriving anything from the call site:
import { NoDelegatedGrantError } from "@alter-ai/alter-sdk";
try {
await vault.request(HttpMethod.GET, "...", { provider: "<provider-id>", userToken: jwt });
} catch (e) {
if (e instanceof NoDelegatedGrantError) {
const session = await vault.createConnectSessionForError(e, {
allowedOrigin: "https://app.example.com",
});
// Surface session.connectUrl to the user — popup, redirect,
// out-of-band message, whatever your framework does.
const results = await vault.pollConnectSession(session.sessionToken);
// Retry with the freshly-minted grantId.
const response = await vault.request(HttpMethod.GET, "...", {
grantId: results[0].grantId,
});
} else {
// Re-throw every other error class so network errors and
// programming bugs aren't silently swallowed.
throw e;
}
}createConnectSessionForError and pollConnectSession are available on both App and Agent so the catch block can recover from whichever client raised.
NoDelegatedGrantError and GrantNotFoundError carry providerId / agentId / appUserId recovery context when the original lookup was identity-mode; CredentialRevokedError carries providerId / appUserId. See the error reference for the full surface.
Onward delegation (agent to agent)
An agent that holds a grant can hand a scoped-down copy to another agent — without asking the credential owner to consent again. Use agent.delegate() to mint a child grant for the second agent:
import { Agent, GrantNotDelegableError } from "@alter-ai/alter-sdk";
const agent = new Agent({ apiKey: "<agent-api-key>" });
try {
const result = await agent.delegate(
"<grant-id>", // a grant this agent already holds
"<other-agent-id>", // the agent that should receive access
{
scopeConstraint: ["chat:write"], // optional: narrow to fewer scopes
ttlSeconds: 3600, // optional: shorten the lifetime
delegable: false, // may the recipient delegate onward? (default no)
},
);
console.log(result.grantId, result.depth, result.expiresAt);
} catch (e) {
if (e instanceof GrantNotDelegableError) {
// The held grant was not marked delegable when it was created,
// so it cannot be passed on. Ask the owner for a delegable grant.
} else {
throw e;
}
}The held grant must have been created as delegable (chosen at connect time). The child can only narrow — fewer scopes, a shorter lifetime — never widen. A grant narrowed with scopeConstraint is proxy-only: call it with agent.proxyRequest(...). Onward delegation is opt-in at every hop: pass delegable: true only when the recipient should be allowed to delegate further.
agent.listGrants() returns each grant with parentGrantId (the grant it was minted under, or null for a root) and depth (its distance from the root), so the full delegation chain can be reconstructed from the flat list.
OpenTelemetry trace propagation
When the application runs an OpenTelemetry SDK, Alter requests automatically carry the active span's W3C traceparent, so the audit trail — and any spans the organization streams to its own OTLP collector — join the application's traces. No configuration is required: @opentelemetry/api is an optional peer dependency that the SDK never installs or requires — when the application has it, the SDK uses it (including under pnpm's isolated mode and Yarn PnP); without it (or without an active span) the SDK behaves exactly as before.
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("the-application");
// `vault` from the quick start above.
await tracer.startActiveSpan("handle-user-request", async (span) => {
try {
// This call's audit events share the surrounding trace's ids.
const response = await vault.request(HttpMethod.GET, url, { grantId });
console.log(response.status);
} finally {
span.end();
}
});Documentation
Full docs are at https://docs.alterauth.com.
| Topic | Page |
|---|---|
| Getting started end-to-end | Quickstart |
| The mental model | How Alter works |
| Calling APIs on behalf of users (OAuth + JWT) | Guide |
| Identity provider setup | Auth0 / Clerk / Okta / WorkOS / Custom OIDC |
| Provisioning backend secrets | Guide |
| Scoped credentials for AI agents | Guide |
| Embedding the Connect widget | Guide |
| Human-in-the-loop approvals | Guide |
| OpenTelemetry trace propagation | Calling APIs |
| Runtime modes (retrieve vs proxy) | Concept |
| Per-method API reference | TypeScript SDK reference |
| Browser popup SDK | @alter-ai/connect |
| Errors | Error reference |
License
MIT. See LICENSE.
Support
Email [email protected] or open an issue at https://github.com/alter-ai/alter-vault.
