Skip to main content

Authentication

The SDK uses account-scoped sessions for secure client-side authentication. This architecture keeps your API keys safe on the server while allowing embedded components to fetch data.

How It Works

┌─────────────┐ 1. Request session ┌─────────────────┐
│ Browser │ ─────────────────────────────▶│ Your Backend │
│ (SDK) │ │ │
│ │ ◀───────────────────────────── │ │
│ │ 4. Return client_secret │ │
└─────────────┘ └────────┬────────┘
│ │
│ 5. API calls with 2. Create session
│ client_secret with API key
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ DialStack API │
└─────────────────────────────────────────────────────────────────┘
  1. Your frontend requests a session from your backend
  2. Your backend creates a session using the Server SDK with your API key
  3. DialStack returns a client_secret scoped to a specific account
  4. Your backend returns the client_secret to the frontend
  5. The SDK uses the client_secret for all API calls

Server-Side: Creating Sessions

Use the Server SDK to create account sessions:

import { DialStack } from '@dialstack/sdk/server';

const dialstack = new DialStack(process.env.DIALSTACK_API_KEY);

// Express.js example
app.post('/api/create-session', async (req, res) => {
const { accountId } = req.body;

const session = await dialstack.accountSessions.create({
account: accountId,
components: {
call_logs: { enabled: true },
voicemails: { enabled: true },
},
});

res.json({
client_secret: session.client_secret,
expires_at: session.expires_at,
});
});

Session Response

interface AccountSessionCreateResponse {
client_secret: string; // Token for client-side use
expires_at: string; // ISO 8601 timestamp
}

Client-Side: Using Sessions

React

import { initialize, DialstackComponentsProvider, CallLogs } from '@dialstack/sdk';
import { useEffect, useState } from 'react';

const dialstack = initialize({
publishableKey: 'pk_live_YOUR_KEY',
});

function App() {
const [clientSecret, setClientSecret] = useState<string | null>(null);

useEffect(() => {
fetch('/api/create-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ accountId: 'acct_01h2xcejqtf2nbrexx3vqjhp41' }),
})
.then((res) => res.json())
.then((data) => setClientSecret(data.client_secret));
}, []);

if (!clientSecret) {
return <div>Loading...</div>;
}

return (
<DialstackComponentsProvider dialstack={dialstack} clientSecret={clientSecret}>
<CallLogs />
</DialstackComponentsProvider>
);
}

Vanilla JavaScript

const dialstack = DialStack.initialize({
publishableKey: 'pk_live_YOUR_KEY',
});

// Fetch session from your backend
const response = await fetch('/api/create-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ accountId: 'acct_01h2xcejqtf2nbrexx3vqjhp41' }),
});
const { client_secret } = await response.json();

// Set on components
const callLogs = document.querySelector('dialstack-call-logs');
callLogs.setClientSecret(client_secret);

Session Expiry

Sessions expire after 1 hour by default. The SDK handles token refresh automatically when you provide the full session response:

// Pass the full response object for automatic refresh handling
<DialstackComponentsProvider
dialstack={dialstack}
clientSecret={{
client_secret: session.client_secret,
expires_at: session.expires_at,
}}
>

The SDK refreshes the session 5 minutes before expiry. If you only pass the client_secret string, you're responsible for refreshing expired sessions.

Component Permissions

Control which components a session can access:

const session = await dialstack.accountSessions.create({
account: accountId,
components: {
call_logs: { enabled: true },
voicemails: { enabled: false }, // Disabled
},
});

Components will show an error if the session doesn't have permission.

Security Best Practices

Keep API Keys Server-Side

Never expose API keys

API keys (sk_live_*) must never appear in client-side code. Only use client_secret tokens in the browser.

// Server-side only
const dialstack = new DialStack(process.env.DIALSTACK_API_KEY);

Validate Account Access

Before creating a session, verify the user has permission to access the requested account:

app.post('/api/create-session', async (req, res) => {
const { accountId } = req.body;
const userId = req.user.id; // From your auth middleware

// Verify user has access to this account
const hasAccess = await verifyAccountAccess(userId, accountId);
if (!hasAccess) {
return res.status(403).json({ error: 'Access denied' });
}

const session = await dialstack.accountSessions.create({
account: accountId,
});

res.json(session);
});

Session Token Security

  • Session tokens cannot create new sessions (prevents escalation)
  • Tokens are scoped to a single account
  • Tokens expire after 1 hour
  • Tokens can only access enabled components

Error Handling

Invalid Session

<CallLogs
onLoadError={(event) => {
if (event.error.includes('session')) {
// Refresh session and retry
refreshSession();
}
}}
/>

Missing Provider

If you forget the provider, you'll see:

Error: Could not find DialStack context; You need to wrap your app
in a <DialstackComponentsProvider> provider.

Next Steps