Skip to main content

Overview

The application uses temporary tokens instead of exposing your AssemblyAI API key directly in the browser. This security model protects your credentials while enabling client-side real-time transcription.

Why Temporary Tokens?

Exposing API keys in browser JavaScript creates serious security risks:
Security Risks of Client-Side API Keys
  • Keys are visible in browser DevTools and page source
  • Keys can be extracted and used by unauthorized parties
  • Compromised keys require rotation and updating all deployments
  • No way to revoke access for individual users or sessions
Temporary tokens solve these problems by:
  1. Time-Limited Access: Tokens expire automatically (configurable from 1 to 600 seconds)
  2. Single-Use: Each browser session gets a fresh token
  3. Revocable: Expired tokens are immediately invalid
  4. Zero Key Exposure: Your API key never leaves the server
Temporary tokens follow the principle of least privilege - granting only the minimum access needed for the specific task.

Server-Side Token Generation

The Express server generates tokens using AssemblyAI’s token endpoint:
tokenGenerator.js
const axios = require('axios');
require("dotenv").config();

async function generateTempToken(expiresInSeconds) {
  const url = `https://streaming.assemblyai.com/v3/token?expires_in_seconds=${expiresInSeconds}`;

  try {
    const response = await axios.get(url, {
      headers: {
        Authorization: process.env.ASSEMBLYAI_API_KEY,
      },
    });
    return response.data.token;
  } catch (error) {
    console.error("Error generating temp token:", error.response?.data || error.message);
    throw error;
  }
}

module.exports = { generateTempToken };
The API key is stored in the .env file and accessed via process.env.ASSEMBLYAI_API_KEY. It’s sent to AssemblyAI’s token endpoint but never transmitted to the browser.

Token Expiration

Tokens are generated with a configurable expiration time:
server.js
app.get("/token", async (req, res) => {
  try {
    const token = await generateTempToken(60); // Max value 600
    res.json({ token });
  } catch (error) {
    res.status(500).json({ error: "Failed to generate token" });
  }
});
This example uses a 60-second expiration. The maximum allowed value is 600 seconds (10 minutes). Choose a duration that balances security with user experience.

Choosing an Expiration Time

  • Short durations (60-120s): Better security, but may interrupt long conversations
  • Medium durations (180-300s): Good balance for most use cases
  • Long durations (300-600s): Better UX, but tokens are valid longer if leaked
For production applications, consider implementing token refresh logic to extend sessions without interrupting the user experience.

Client-Side Token Usage

The browser requests a token before establishing the WebSocket connection:
index.js
async function run() {
  // ... microphone setup ...

  // Request token from server
  const response = await fetch("http://localhost:8000/token");
  const data = await response.json();
  if (data.error || !data.token) {
    alert("Failed to get temp token");
    return;
  }

  // Use token in WebSocket URL
  const endpoint = `wss://streaming.assemblyai.com/v3/ws?sample_rate=16000&formatted_finals=true&token=${data.token}`;
  ws = new WebSocket(endpoint);
}
The token is passed as a query parameter in the WebSocket URL. AssemblyAI validates the token when the connection is established.

Token Lifecycle

Token Validation

AssemblyAI validates tokens when:
  1. WebSocket Connection: Token is checked when the connection is established
  2. During Streaming: If a token expires mid-session, the connection is closed
If a connection is closed due to token expiration, the ws.onclose handler will fire. The application would need to request a new token and reconnect.

Error Handling

The token generation endpoint includes error handling:
server.js
app.get("/token", async (req, res) => {
  try {
    const token = await generateTempToken(60);
    res.json({ token });
  } catch (error) {
    res.status(500).json({ error: "Failed to generate token" });
  }
});
Common errors:
  • Invalid API Key: Check that your .env file contains the correct key
  • Network Issues: AssemblyAI’s token endpoint may be unreachable
  • Rate Limiting: Too many token requests in a short time
Always handle token request failures gracefully. Display clear error messages to users and log detailed errors for debugging.

Security Best Practices

API Key Storage
  • Store API keys in .env files
  • Never commit .env files to version control
  • Add .env to your .gitignore
  • Use environment variables in production
Token Management
  • Use the shortest practical expiration time
  • Generate a new token for each session
  • Don’t cache tokens on the client
  • Validate token requests server-side
Production Considerations
  • Implement rate limiting on your /token endpoint
  • Add authentication/authorization for your users
  • Consider implementing token refresh logic
  • Monitor token generation for unusual patterns

Environment Variables

The .env file should contain your AssemblyAI API key:
.env
ASSEMBLYAI_API_KEY=your_api_key_here
Get your API key from the AssemblyAI dashboard. Never share or commit this key.

Token Request Flow

  1. User Clicks Record: Triggers the run() function
  2. Client Requests Token: fetch("http://localhost:8000/token")
  3. Server Validates Request: Express endpoint receives the request
  4. Server Generates Token: Calls AssemblyAI’s token API with your API key
  5. Server Returns Token: Sends token back to client as JSON
  6. Client Connects: Uses token in WebSocket URL to connect to AssemblyAI
This flow ensures your API key is only used server-side, where it’s protected from client-side extraction.

Build docs developers (and LLMs) love