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 │
└─────────────────────────────────────────────────────────────────┘
- Your frontend requests a session from your backend
- Your backend creates a session using the Server SDK with your API key
- DialStack returns a
client_secretscoped to a specific account - Your backend returns the
client_secretto the frontend - The SDK uses the
client_secretfor 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
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
- React Components - Build with React
- Server SDK - Full server-side API
- Theming - Customize appearance