Skip to main content

Authentication

Learn how to authenticate API requests using API keys and JWT tokens.

Two Authentication Methods

The Control API uses two different authentication methods:

1. Kaltura Session (KS) (for session creation)

2. JWT Token (for session control)

Kaltura Session (KS) Authentication

Used for: Creating new sessions

Header: Authorization: KS <ks>

Example:

curl -X POST https://api.avatar.us.kaltura.ai/v1/avatar-session/create \
-H "Authorization: KS your-kaltura-session-here" \
-H "Content-Type: application/json" \
-d '{"visualConfig": {"avatarId": "avatar-123"}}'

Getting Your Kaltura Session

You can generate a Kaltura Session (KS) using the Kaltura API. See the Kaltura Session Creation Guide for detailed instructions.

Alternatively, contact your Kaltura representative for assistance.

Storing Your Kaltura Session

Security

NEVER expose your Kaltura Session in:

  • Client-side code
  • Frontend applications
  • Public repositories
  • Browser DevTools

ALWAYS store it:

  • In environment variables
  • In secure secret managers
  • On your backend server only

Good practices:

# .env file
AVATAR_KS=your-kaltura-session-here
// Node.js
const KS = process.env.AVATAR_KS;
# Python
import os
KS = os.environ.get('AVATAR_KS')

JWT Token Authentication

Used for: All session operations (except creation)

Header: Authorization: Bearer {token}

Example:

curl -X POST https://api.avatar.us.kaltura.ai/v1/avatar-session/:sessionId/say-text \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{"text": "Hello!"}'

How to Get a Token

The JWT token is returned when you create a session:

const response = await fetch('https://api.avatar.us.kaltura.ai/v1/avatar-session/create', {
method: 'POST',
headers: {
Authorization: `KS ${process.env.AVATAR_KS}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
visualConfig: { avatarId: 'avatar-123' },
}),
});

const data = await response.json();
console.log('Token:', data.token); // JWT token here
console.log('Session ID:', data.sessionId);

Token Properties

  • Scope: Valid only for the specific session
  • Expiration: Tied to session lifetime
  • Permissions: Full control over the session
  • Single use: One token per session

Using the Token

// After creating session
const { sessionId, token } = await createSession();

// Use token for all operations
await fetch(`https://api.avatar.us.kaltura.ai/v1/avatar-session/${sessionId}/say-text`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: 'Hello!' }),
});

Authentication Flow

┌──────────────┐
│ Backend │
│ │
│ 1. Store │
│ KS │
└──────┬───────┘

│ Create session with KS

┌──────────────┐
│ Avatar API │
│ │
│ 2. Validate │
│ KS │
│ │
│ 3. Generate │
│ JWT token │
└──────┬───────┘

│ Return sessionId + token

┌──────────────┐
│ Backend │
│ │
│ 4. Send to │
│ frontend │
└──────┬───────┘

│ sessionId + token

┌──────────────┐
│ Frontend │
│ │
│ 5. Use token │
│ for │
│ display │
└──────────────┘

Complete Example

Backend Server

import express from 'express';
import fetch from 'node-fetch';

const app = express();
app.use(express.json());

// Kaltura Session stored securely
const AVATAR_KS = process.env.AVATAR_KS;
const AVATAR_BASE_URL = 'https://api.avatar.us.kaltura.ai/v1/avatar-session';

// Session storage (in-memory for demo, use database in production)
const sessions = new Map();

// Create session endpoint
app.post('/api/avatar/create-session', async (req, res) => {
try {
// Call Kaltura API with KS
const response = await fetch(`${AVATAR_BASE_URL}/create`, {
method: 'POST',
headers: {
Authorization: `KS ${AVATAR_KS}`, // Secure on server
'Content-Type': 'application/json',
},
body: JSON.stringify({
visualConfig: { avatarId: req.body.avatarId },
voiceConfig: req.body.voiceId ? { id: req.body.voiceId } : undefined,
}),
});

if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}

const data = await response.json();

// Store session info
sessions.set(data.sessionId, {
token: data.token,
createdAt: new Date(),
});

// Return to frontend (token is safe to send)
res.json({
sessionId: data.sessionId,
token: data.token,
});
} catch (error) {
console.error('Failed to create session:', error);
res.status(500).json({ error: 'Failed to create session' });
}
});

// Control endpoint (uses token)
app.post('/api/avatar/say-text', async (req, res) => {
try {
const { sessionId, token, text } = req.body;

// Verify session exists
if (!sessions.has(sessionId)) {
return res.status(404).json({ error: 'Session not found' });
}

// Call Kaltura API with token
const response = await fetch(`${AVATAR_BASE_URL}/${sessionId}/say-text`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text }),
});

if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}

const data = await response.json();
res.json(data);
} catch (error) {
console.error('Failed to say text:', error);
res.status(500).json({ error: 'Failed to say text' });
}
});

Frontend Client

// Create session (token from backend)
const { sessionId, token } = await fetch('/api/avatar/create-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
avatarId: 'avatar-123',
voiceId: 'voice-456',
}),
}).then((r) => r.json());

console.log('Session ID:', sessionId);
console.log('Token:', token);

// Use token for display
import { KalturaAvatarSession } from '@unisphere/models-sdk-js';

const session = new KalturaAvatarSession(token, {
baseUrl: 'https://api.avatar.us.kaltura.ai/v1/avatar-session',
});

session.attachAvatar('avatar-container');

// Control from backend
await fetch('/api/avatar/say-text', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionId,
token,
text: 'Hello from the backend!',
}),
});

Error Responses

401 Unauthorized

Kaltura Session:

{
"success": false,
"error": "Invalid Kaltura Session"
}

Causes:

  • Kaltura Session is missing
  • Kaltura Session is invalid
  • Kaltura Session is expired

Solutions:

  • Verify Kaltura Session is correct
  • Check Authorization: KS <ks> header is set
  • Contact Kaltura for new session

Token:

{
"success": false,
"error": "Invalid or expired token"
}

Causes:

  • Token is missing
  • Token is invalid
  • Session has ended
  • Token has expired

Solutions:

  • Verify token is correct
  • Check Authorization: Bearer {token} header
  • Create a new session if needed

403 Forbidden

{
"success": false,
"error": "Insufficient permissions"
}

Causes:

  • Kaltura Session doesn't have required permissions
  • Token doesn't match session

Security Best Practices

1. Kaltura Session Security

DO:

  • Store in environment variables
  • Use secret managers (AWS Secrets Manager, Azure Key Vault)
  • Rotate sessions regularly
  • Limit session scope if possible

DON'T:

  • Commit to version control
  • Include in client code
  • Share via email or chat
  • Log in plain text

2. Token Security

DO:

  • Send tokens over HTTPS only
  • Store tokens temporarily
  • Clear tokens when session ends
  • Validate tokens server-side

DON'T:

  • Store tokens long-term
  • Share tokens between users
  • Log tokens in plain text

3. HTTPS Only

Always use HTTPS in production:

// ❌ Bad - HTTP
const baseUrl = 'http://api.avatar.example.com';

// ✅ Good - HTTPS
const baseUrl = 'https://api.avatar.example.com';

4. Request Validation

Validate all requests before calling the API:

app.post('/api/avatar/say-text', async (req, res) => {
// Validate input
if (!req.body.text || req.body.text.length > 1000) {
return res.status(400).json({ error: 'Invalid text' });
}

// Validate session exists
if (!sessions.has(req.body.sessionId)) {
return res.status(404).json({ error: 'Session not found' });
}

// Call API
// ...
});

Next Steps