npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@alter-ai/connect

v0.3.0

Published

JavaScript SDK for Alter Connect - Secure OAuth integration UI

Readme

Alter Connect SDK

A lightweight JavaScript SDK for embedding OAuth integrations into your application. The SDK opens a backend-served Connect UI in a popup — the backend handles auth, provider selection, branding, and OAuth, then sends results back via postMessage.

~10KB minified | Zero dependencies | TypeScript included

Quick Start

1. Install

npm install @alter-ai/connect

Or use via CDN:

<script src="https://cdn.jsdelivr.net/npm/@alter-ai/connect@latest/dist/alter-connect.umd.js"></script>

2. Get a Session Token from Your Backend

Your backend creates a short-lived session token using the Alter SDK:

// YOUR backend (Node.js example using @alter-ai/alter-sdk)
import { AlterVault, ActorType } from "@alter-ai/alter-sdk";

const vault = new AlterVault({
  apiKey: process.env.ALTER_API_KEY!,
  actorType: ActorType.BACKEND_SERVICE,
  actorIdentifier: "my-backend",
});

const session = await vault.createConnectSession({
  endUser: { id: "user_123" },
  allowedProviders: ["google", "slack", "github"],
  returnUrl: "https://yourapp.com/callback",
});

const session_token = session.sessionToken;

3. Open the Connect UI

import AlterConnect from '@alter-ai/connect';

// Initialize SDK (no API key needed!)
const alterConnect = AlterConnect.create();

// Get session token from YOUR backend
const { session_token } = await fetch('/api/alter/session').then(r => r.json());

// Open Connect UI
await alterConnect.open({
  token: session_token,
  onSuccess: (connections) => {
    console.log('Connected!', connections);
    // Save each connection.connection_id to your database
    connections.forEach(conn => console.log(conn.provider, conn.connection_id));
  },
  onError: (error) => {
    console.error('Failed:', error);
  },
  onExit: () => {
    console.log('User closed the window');
  }
});

That's it! The SDK handles the OAuth flow, popup windows, mobile redirects, and all security.

Framework Examples

React

import { useState } from 'react';
import AlterConnect from '@alter-ai/connect';

function ConnectButton() {
  const [alterConnect] = useState(() => AlterConnect.create());

  const handleConnect = async () => {
    const { session_token } = await fetch('/api/alter/session')
      .then(r => r.json());

    await alterConnect.open({
      token: session_token,
      onSuccess: (connections) => {
        console.log('Connected!', connections);
      }
    });
  };

  return <button onClick={handleConnect}>Connect Account</button>;
}

Vue

<template>
  <button @click="handleConnect">Connect Account</button>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import AlterConnect from '@alter-ai/connect';

const alterConnect = ref(null);

onMounted(() => {
  alterConnect.value = AlterConnect.create();
});

async function handleConnect() {
  const { session_token } = await fetch('/api/alter/session')
    .then(r => r.json());

  await alterConnect.value.open({
    token: session_token,
    onSuccess: (connections) => console.log('Connected!', connections)
  });
}
</script>

Vanilla JavaScript (CDN)

<button id="connect-btn">Connect Account</button>

<script src="https://cdn.jsdelivr.net/npm/@alter-ai/connect@latest/dist/alter-connect.umd.js"></script>
<script>
  const alterConnect = AlterConnect.create();

  document.getElementById('connect-btn').addEventListener('click', async () => {
    const { session_token } = await fetch('/api/alter/session')
      .then(r => r.json());

    await alterConnect.open({
      token: session_token,
      onSuccess: (connections) => console.log('Connected!', connections)
    });
  });
</script>

API Reference

AlterConnect.create(config?)

Creates a new SDK instance.

const alterConnect = AlterConnect.create({
  debug: true  // Enable console logging (default: false)
});

| Option | Type | Description | Default | |--------|------|-------------|---------| | debug | boolean | Enable debug logging | false |

Note: Visual customization (colors, fonts, logo) is configured via the Developer Portal branding settings. The backend-served Connect UI applies your branding automatically.


alterConnect.open(options)

Opens the Connect UI. On desktop, opens a centered popup window (500x700px). On mobile, uses a full-page redirect flow.

await alterConnect.open({
  token: 'sess_abc123...',
  // baseURL is auto-detected; override only for custom deployments
  onSuccess: (connections) => { /* ... */ },
  onError: (error) => { /* ... */ },
  onExit: () => { /* ... */ },
  onEvent: (eventName, metadata) => { /* ... */ }
});

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | token | string | Yes | Session token from your backend | | baseURL | string | No | Alter API URL (usually auto-detected) | | onSuccess | function | Yes | Called with array of connections on success | | onError | function | No | Called when connection fails | | onExit | function | No | Called when user closes popup | | onEvent | function | No | Called for analytics events |

Connections Array (onSuccess):

onSuccess receives an array of Connection objects (multi-provider flow):

// Each connection in the array:
{
  connection_id: string;        // Unique ID - store this!
  provider: string;             // e.g., 'google', 'slack'
  provider_name: string;        // e.g., 'Google', 'Slack'
  account_identifier: string;   // e.g., '[email protected]'
  timestamp: string;            // ISO 8601 timestamp
  operation: 'creation' | 'reauth' | 'grant';
  scopes: string[];             // Granted OAuth scopes
  status: 'active' | 'pending' | 'error';
  metadata?: {
    account_display_name?: string;
    account_email?: string;
  };
}

Error Object (onError):

{
  code: string;     // e.g., 'invalid_token', 'popup_blocked'
  message: string;  // Human-readable message
  details?: object; // Additional error context
}

alterConnect.close()

Manually closes the Connect UI.

alterConnect.close();

alterConnect.destroy()

Destroys the SDK instance and cleans up resources.

alterConnect.destroy();

alterConnect.on(event, handler)

Register an event listener. Returns an unsubscribe function.

const unsubscribe = alterConnect.on('success', (connection) => {
  console.log('Connected:', connection);
});

// Later: unsubscribe();

Events: success, error, exit, close, event


alterConnect.isOpen()

Checks if the Connect UI is currently open.

if (alterConnect.isOpen()) {
  console.log('Modal is open');
}

alterConnect.getVersion()

Gets the SDK version.

console.log(alterConnect.getVersion()); // "0.2.0"

Mobile Support

The SDK automatically detects mobile devices and switches to an optimized flow:

| Device | Flow | How It Works | |--------|------|-------------| | Desktop | Popup | Opens centered popup (500x700px), communicates via postMessage | | Phone (<=480px) | Redirect | Full-page redirect, returns via URL params | | Tablet (portrait) | Redirect | Full-page redirect for better UX | | Tablet (landscape) | Popup | Uses popup flow like desktop |

No code changes needed — the SDK handles device detection automatically.

For mobile redirect flow, include a return_url when creating the session:

// Backend session creation with mobile support
body: JSON.stringify({
  end_user: { id: 'user_123', email: '[email protected]' },
  allowed_providers: ['google', 'slack'],
  allowed_origin: 'https://yourapp.com',  // For desktop popup (postMessage)
  return_url: 'https://yourapp.com/'      // For mobile redirect (return destination)
})

Security Architecture

The SDK uses a Plaid-style token architecture:

Frontend (Public)          Backend (Secure)           Alter API
     │                          │                        │
     │  1. User clicks          │                        │
     │     "Connect"            │                        │
     │─────────────────────────>│                        │
     │                          │                        │
     │                          │  2. Create session     │
     │                          │     (with API key)     │
     │                          │───────────────────────>│
     │                          │                        │
     │                          │  3. { session_token }  │
     │                          │<───────────────────────│
     │                          │                        │
     │  4. { session_token }    │                        │
     │<─────────────────────────│                        │
     │                          │                        │
     │  5. SDK opens popup to backend Connect UI         │
     │───────────────────────────────────────────────────>│
     │                          │                        │
     │     6. Backend handles auth + OAuth               │
     │                          │                        │
     │  7. postMessage(connection)                       │
     │<──────────────────────────────────────────────────│
     │  8. onSuccess(connections) │                        │

Key Security Features:

  • API keys never touch frontend - Only backend has API key
  • Session tokens are short-lived - Expire after 10 minutes
  • Session tokens are single-use - Can only create one connection
  • Session tokens are scoped - Locked to specific user & providers
  • No secrets in browser - SDK is purely a popup launcher + callback listener

Smart UX

Single Provider Flow

When only 1 provider is allowed, the Connect UI skips the selection screen and opens OAuth directly:

// Backend: allowed_providers: ['google']
// Result: Opens Google OAuth immediately (no selection screen)

Multiple Provider Flow

When 2+ providers are allowed, the Connect UI shows a provider selection screen:

// Backend: allowed_providers: ['google', 'slack', 'github']
// Result: Shows provider selection, user picks one

TypeScript Support

Full TypeScript definitions included:

import AlterConnect, {
  AlterConnectConfig,
  Connection,
  AlterError
} from '@alter-ai/connect';

const alterConnect = AlterConnect.create({ debug: true });

await alterConnect.open({
  token: sessionToken,
  onSuccess: (connections: Connection[]) => {
    console.log(connection.connection_id);
    console.log(connection.provider);
    console.log(connection.scopes);
  },
  onError: (error: AlterError) => {
    console.error(error.code, error.message);
  }
});

Bundle Size

| Format | Size | Gzipped | |--------|------|---------| | CJS | ~10KB | ~3.5KB | | ESM | ~10KB | ~3.4KB | | UMD | ~11KB | ~3.5KB |

Zero runtime dependencies.

Browser Support

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+
  • Mobile browsers (iOS Safari 14+, Chrome Mobile)

Troubleshooting

Popup Blocked

Problem: Browser blocks the OAuth popup

Solution: Ensure alterConnect.open() is called directly from a user interaction (click event):

// Bad - may be blocked
button.addEventListener('click', async () => {
  const token = await fetchToken(); // Async delay
  alterConnect.open({ token }); // May be blocked
});

// Good - no async delay before open()
button.addEventListener('click', () => {
  fetchToken().then(token => {
    alterConnect.open({ token }); // Called synchronously
  });
});

Session Token Expired

Problem: session_expired error

Solution: Session tokens expire after 10 minutes. Create a new session token.

CORS Errors

Problem: CORS error when calling Alter API

Solution: Session tokens should be created from your backend, not frontend. The SDK handles all frontend API calls.

Support

License

MIT License - See LICENSE file for details