Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.alterauth.com/llms.txt

Use this file to discover all available pages before exploring further.

Get started with the Alter SDK for TypeScript to make authenticated API calls to any OAuth provider, manage connections, and create connect sessions. The SDK supports OAuth tokens, API keys, and custom credentials, all retrieved and injected automatically.

Installation

Requires Node.js 20 or higher. TypeScript 5.0+ recommended.
npm install @alter-ai/alter-sdk

Basic Setup

import { AlterVault, HttpMethod } from "@alter-ai/alter-sdk";

const vault = new AlterVault({
  apiKey: "alter_key_...",
  caller: "my-agent",
});

const response = await vault.request(
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
  {
    grantId: "GRANT_ID",  // from Alter Connect (see below)
    queryParams: { maxResults: "10" },
  }
);

const events = await response.json();
for (const event of events.items ?? []) {
  console.log(`Event: ${event.summary}`);
}

await vault.close();
Key Principle: Zero Token Exposure — You never see or handle OAuth tokens. The SDK retrieves them from Alter Vault and injects them automatically. All SDK-to-backend communication is cryptographically secured for integrity, authenticity, and replay protection.

Configuration

import { AlterVault, CallerType } from "@alter-ai/alter-sdk";

const vault = new AlterVault({
  apiKey: "alter_key_...",              // Required: API key from dashboard
  caller: "my-agent",                  // Optional: Caller identity for audit logs
  callerType: CallerType.AGENT,        // Optional: AGENT (default) or SERVICE
  timeout: 30000,                      // Optional: HTTP timeout in milliseconds
});
Use CallerType.SERVICE for backend infrastructure callers that should not appear in the Developer Portal Agents tab. Audit logging is always enabled and cannot be disabled — every API call is automatically logged for compliance. The SDK automatically includes the HTTP method and target URL in the audit trail for each token request.

Connecting an Identity Provider

If the application uses an external IDP (Okta, Entra ID, Auth0, Clerk, Keycloak, or any OIDC issuer), wire it up to the SDK so every request is scoped to the signed-in end user. This is required for provider lookups (identity-based grant resolution) and powers group-based policies and instant deprovisioning. One-time setup (Developer Portal): add the IDP to the application on its Identity page — paste the OIDC issuer URL, click Discover, then save. Alter Vault auto-detects the IDP type and claim mappings.
Single-IDP rule: each application can have only one active identity provider configuration at a time. To switch providers, remove the current IDP and add the replacement, then update JWT issuer settings and webhook/OIDC credentials for the replacement.
See the IDP Setup Guide for per-provider steps. Per-request wiring (SDK): pass a userTokenGetter that returns the end user’s IDP-issued JWT. The SDK attaches it to every token request so the backend can resolve the user from the JWT claims.
import { AlterVault, HttpMethod } from "@alter-ai/alter-sdk";

const vault = new AlterVault({
  apiKey: "alter_key_...",
  caller: "my-agent",
  // Called before every request — return a fresh JWT for the current user.
  // Sync or async functions are both supported.
  userTokenGetter: () => getCurrentUserJwt(),
});

// `provider` looks up the grant that belongs to the JWT's user — no grantId needed.
const response = await vault.request(
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
  { provider: "google" },
);
Two resolution modes — pass grantId when the caller already knows the exact grant, or pass provider with an active end-user token source so the backend can resolve the grant from the JWT’s sub claim. The token source can come from constructor userTokenGetter or from a token cached via vault.authenticate().
End-user login flow (optional): if the application does not already have a JWT for the user, call vault.authenticate() to open a browser-based OIDC login through the IDP and receive the user profile. The SDK caches the resulting token internally and installs it as the active token getter for that AlterVault instance (overriding any constructor-supplied userTokenGetter) — configure the IDP’s wallet/SDK client credentials in the Developer Portal first.
const authResult = await vault.authenticate();
console.log(authResult.userInfo); // { sub, email, name, ... } from the IDP

Quick Error Handling

import {
  ReAuthRequiredError,
  ScopeReauthRequiredError,
  PolicyViolationError,
  TokenRefreshInProgressError,
  GrantNotFoundError,
  AmbiguousGrantError,
} from "@alter-ai/alter-sdk";

try {
  // Identity mode — the SDK resolves the grant from the configured
  // userTokenGetter. AmbiguousGrantError can only be raised on this
  // path; direct (grantId) mode addresses a single grant.
  const response = await vault.request(
    HttpMethod.GET,
    "https://www.googleapis.com/calendar/v3/calendars/primary/events",
    { provider: "google" },
  );
  return await response.json();
} catch (e) {
  if (e instanceof ScopeReauthRequiredError) {
    console.log(`Scopes changed — user must re-authorize (provider: ${e.providerId}, connection: ${e.grantId})`);
  } else if (e instanceof ReAuthRequiredError) {
    console.log("User must re-authorize via Alter Connect");
  } else if (e instanceof PolicyViolationError) {
    console.log(`Access denied by policy: ${e.message} (rule: ${e.policyError})`);
  } else if (e instanceof TokenRefreshInProgressError) {
    // Another request is mid-refresh — transient, retry after backoff
    console.log(`Token refresh in progress for ${e.grantId} — retry after backoff`);
  } else if (e instanceof AmbiguousGrantError) {
    // JWT identity resolution matched multiple active grants — supply
    // `account` to disambiguate. Matching identifiers are exposed on the
    // exception so the caller can prompt or pick.
    console.log(`Multiple grants for ${e.providerId}:`, e.accountIdentifiers);
  } else if (e instanceof GrantNotFoundError) {
    console.log("User hasn't connected Google yet");
  } else {
    throw e;
  }
} finally {
  await vault.close();
}

Revoking a Grant

Permanently revoke a grant when it’s no longer needed. Tokens are deleted from Vault and the grant status is set to revoked. The user must re-authorize via Alter Connect to restore access.
const result = await vault.revokeGrant(grantId, {
  reason: "Agent cleanup: stale grant", // optional; stored in the audit log
});
console.log(`Revoked at ${result.revokedAt}`);
revokeGrant() throws GrantNotFoundError if the grant does not exist or is already revoked. When the AlterVault instance has userTokenGetter configured, revokeGrant() targets a grant owned by the authenticated caller — passing a grantId that belongs to someone else throws GrantNotFoundError. See Scoping grant operations to the authenticated user in the overview.

Provisioning Managed-Secret Grants

createManagedSecretGrant() ties a managed secret to a specific principal (user, IDP group, or system). Use it when an admin or backend job needs to provision access without sending the end user through Alter Connect.
import {
  AlterVault,
  type GroupPrincipal,
  type UserPrincipal,
  type SystemPrincipal,
} from "@alter-ai/alter-sdk";

// Tie the secret to an IDP group — every member with a verified JWT gets access
const groupGrant = await vault.createManagedSecretGrant("a1b2c3d4-5e6f-7890-abcd-ef0123456789", {
  principal: {
    type: "group",
    idpId: "idp_xyz",
    externalGroupId: "okta-group-engineering",
    label: "engineering-prod-stripe",
  } satisfies GroupPrincipal,
});

// Tie the secret to a specific end user (validates userToken against the IDP).
// `label` is required so the wallet can render meaningful copy.
const userGrant = await vault.createManagedSecretGrant("a1b2c3d4-5e6f-7890-abcd-ef0123456789", {
  principal: {
    type: "user",
    userToken: currentUserJwt,
    label: "alice-prod-stripe-readonly",
  } satisfies UserPrincipal,
});

// Headless system grant — no end-user identity required. `label` is optional
// because system grants typically don't surface in the wallet.
const systemGrant = await vault.createManagedSecretGrant("a1b2c3d4-5e6f-7890-abcd-ef0123456789", {
  principal: { type: "system", label: "cron-stripe-charges" } satisfies SystemPrincipal,
});

console.log(groupGrant.grantId, groupGrant.principalType);
Principal is a discriminated union (type field is the discriminator). label is required on UserPrincipal and GroupPrincipal (rendered in the wallet) and optional on SystemPrincipal. The backend resolves and persists the principal: UserPrincipal validates the JWT and binds the grant to the resolved app user; GroupPrincipal upserts the IDP group; SystemPrincipal records a headless grant — anyone with the grant id and a valid signature for the app can retrieve the credential, so use only for backend flows with no caller user.

Next Steps

SDK Overview

Core concepts, complete examples, actor tracking, and error handling

Quickstart Guide

Full integration walkthrough with frontend + backend

Python SDK

Python SDK equivalent