@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/connectOr 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 oneTypeScript 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
- Documentation: https://docs.alterai.dev
- Issues: GitHub Issues
- Email: [email protected]
License
MIT License - See LICENSE file for details
