> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.aiola.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.aiola.ai/_mcp/server.

# Authentication

> Learn how aiOla's authentication system works, its security benefits, and best practices for implementation.

aiOla uses a secure two-tier authentication system that combines API keys with JWT access tokens. This approach provides both security and flexibility, allowing you to keep sensitive credentials on the backend while enabling frontend applications to make authenticated requests.

## How Authentication Works

### Overview

aiOla's authentication flow follows this pattern:

1. **API Key Exchange**: Your backend application uses an API key to request an access token
2. **Token Generation**: aiOla's authentication service returns a JWT access token
3. **API Requests**: Your application uses the access token to make authenticated requests to aiOla services

```mermaid
sequenceDiagram
    participant Frontend
    participant Backend
    participant aiOla Auth
    participant aiOla API
    
    Frontend->>Backend: Request access token
    Backend->>aiOla Auth: Create access token using API Key
    aiOla Auth-->>Backend: JWT Access Token
    Backend-->>Frontend: Access Token
    Frontend->>aiOla API: API Request + Bearer Token
    aiOla API-->>Frontend: Response
```

### Why This Architecture?

This two-tier system provides several key benefits:

#### 🔐 **Enhanced Security**

* **API Key Protection**: Your sensitive API key never leaves your backend
* **Token Rotation**: Access tokens have limited lifespans and can be rotated regularly
* **Principle of Least Privilege**: Frontend applications only receive temporary access tokens

#### 🏗️ **Architectural Flexibility**

* **Frontend Freedom**: Client applications can authenticate without exposing secrets
* **Scalable Design**: Generate tokens for multiple clients from a single API key
* **Environment Separation**: Different tokens for development, staging, and production

#### 🛡️ **Risk Mitigation**

* **Limited Exposure**: If a token is compromised, it expires automatically
* **Centralized Control**: Revoke access by rotating the API key on your backend
* **Audit Trail**: Track token generation and usage patterns

## Implementation Guide

### Backend: Token Generation

Your backend is responsible for exchanging API keys for access tokens:

#### Python

```python
import os
from aiola import AiolaClient

# Generate an access token using your API key
def get_access_token():
    try:
        result = AiolaClient.grant_token(
            api_key=os.getenv("AIOLA_API_KEY")
        )
        return {
            "access_token": result.access_token,
            "session_id": result.session_id,
        }
    except Exception as e:
        print(f"Token generation failed: {e}")
        return None

# Create client with access token
def create_client(access_token):
    return AiolaClient(access_token=access_token)
```

#### TypeScript

```typescript
import { AiolaClient } from '@aiola/sdk';

interface TokenResponse {
  access_token: string;
  session_id: string;
}

// Generate an access token using your API key
const getAccessToken = async (): Promise<TokenResponse | null> => {
  try {
    const result = await AiolaClient.grantToken({
      apiKey: process.env.AIOLA_API_KEY!
    });
    return {
      access_token: result.accessToken,
      session_id: result.sessionId,
    };
  } catch (error) {
    console.error(`Token generation failed: ${error}`);
    return null;
  }
};

// Create client with access token
const createClient = (accessToken: string): AiolaClient => {
  return new AiolaClient({ accessToken });
};
```

### Frontend: Using Access Tokens

Once you have an access token, use it in the Authorization header:

#### JavaScript

```javascript
import { AiolaClient } from '@aiola/sdk';

// Generate access token (typically done on backend)
const getAccessToken = async () => {
  try {
    const { accessToken, sessionId } = await AiolaClient.grantToken({
      apiKey: process.env.AIOLA_API_KEY
    });
    return { accessToken, sessionId };
  } catch (error) {
    console.error('Token generation failed:', error);
    throw error;
  }
};

// Create client and use for requests
const makeAiolaRequest = async (audioData) => {
  const { accessToken } = await getAccessToken();
  
  const client = new AiolaClient({ accessToken });
  
  const transcript = await client.stt.transcribeFile({
    file: audioData,
    language: 'en'
  });
  
  return transcript;
};
```

#### Python

```python
from aiola import AiolaClient
import os

def get_access_token():
    result = AiolaClient.grant_token(
        api_key=os.getenv('AIOLA_API_KEY')
    )
    return result.access_token

def transcribe_audio(audio_file_path):
    # Generate token and create client
    access_token = get_access_token()
    client = AiolaClient(access_token=access_token)
    
    with open(audio_file_path, 'rb') as audio_file:
        transcript = client.stt.transcribe_file(
            file=audio_file,
            language='en'
        )
    
    return transcript
```

## Security Best Practices

### API Key Management

> **Warning**
>
> **Never expose your API key in frontend code or version control**

#### ✅ **Do:**

* Store API keys in environment variables
* Use secure secret management systems in production
* Rotate API keys regularly
* Limit API key access to necessary backend services only

#### ❌ **Don't:**

* Include API keys in frontend applications
* Commit API keys to version control
* Share API keys across environments
* Store API keys in plain text files

### Token Handling

#### **Backend Token Management**

#### Python

```python
import os
from datetime import datetime, timedelta
import redis

# Example token caching to avoid unnecessary API calls
redis_client = redis.Redis(host='localhost', port=6379)

def get_cached_token():
    cached_token = redis_client.get('aiola_access_token')
    if cached_token:
        return cached_token.decode('utf-8')
    
    # Generate new token
    token_data = client.grant_token()
    
    # Cache token with expiration buffer (5 minutes before actual expiry)
    cache_duration = token_data.expires_in - 300
    redis_client.setex('aiola_access_token', cache_duration, token_data.access_token)
    
    return token_data.access_token
```

#### TypeScript

```typescript
import Redis from 'ioredis';
import { AiolaClient } from '@aiola/sdk';

// Example token caching to avoid unnecessary API calls
const redisClient = new Redis({
  host: 'localhost',
  port: 6379
});

interface TokenData {
  accessToken: string;
  expiresIn: number;
}

const getCachedToken = async (): Promise<string> => {
  const cachedToken = await redisClient.get('aiola_access_token');
  if (cachedToken) {
    return cachedToken;
  }
  
  // Generate new token
  const tokenData: TokenData = await client.grantToken();
  
  // Cache token with expiration buffer (5 minutes before actual expiry)
  const cacheDuration = tokenData.expiresIn - 300;
  await redisClient.setex('aiola_access_token', cacheDuration, tokenData.accessToken);
  
  return tokenData.accessToken;
};
```

#### **Frontend Token Management**

#### JavaScript

```javascript
class TokenManager {
  constructor() {
    this.token = null;
    this.tokenExpiry = null;
  }
  
  async getValidToken() {
    // Check if current token is still valid (with 5-minute buffer)
    if (this.token && this.tokenExpiry > Date.now() + 300000) {
      return this.token;
    }
    
    // Fetch new token from backend
    const tokenData = await this.fetchTokenFromBackend();
    this.token = tokenData.access_token;
    this.tokenExpiry = Date.now() + (tokenData.expires_in * 1000);
    
    return this.token;
  }
  
  async fetchTokenFromBackend() {
    const response = await fetch('/api/auth/token');
    if (!response.ok) {
      throw new Error('Failed to fetch access token');
    }
    return response.json();
  }
}
```

#### TypeScript

```typescript
interface TokenData {
  access_token: string;
  expires_in: number;
}

class TokenManager {
  private token: string | null = null;
  private tokenExpiry: number | null = null;
  
  async getValidToken(): Promise<string> {
    // Check if current token is still valid (with 5-minute buffer)
    if (this.token && this.tokenExpiry && this.tokenExpiry > Date.now() + 300000) {
      return this.token;
    }
    
    // Fetch new token from backend
    const tokenData = await this.fetchTokenFromBackend();
    this.token = tokenData.access_token;
    this.tokenExpiry = Date.now() + (tokenData.expires_in * 1000);
    
    return this.token;
  }
  
  private async fetchTokenFromBackend(): Promise<TokenData> {
    const response = await fetch('/api/auth/token');
    if (!response.ok) {
      throw new Error('Failed to fetch access token');
    }
    return response.json();
  }
}
```

## Environment Configuration

### Development Setup

```bash
# .env file
AIOLA_API_KEY=your-development-api-key
AIOLA_ENDPOINT=https://api.aiola.com
```

### Production Setup

For production deployments, consider:

#### **Enterprise Endpoints**

```bash
# Custom enterprise endpoint
AIOLA_ENDPOINT=https://your-company.aiola-enterprise.com
AIOLA_API_KEY=your-production-api-key
```

#### **Enterprise Configuration**

#### Python

```python
# Enterprise/custom endpoint configuration
result = AiolaClient.grant_token(
    api_key=os.getenv("AIOLA_API_KEY"),
    auth_base_url="https://your-company.auth.aiola.ai"
)

client = AiolaClient(
    access_token=result.access_token,
    base_url="https://your-company.api.aiola.ai"
)
```

#### TypeScript

```typescript
// Enterprise/custom endpoint configuration
const result = await AiolaClient.grantToken({
  apiKey: process.env.AIOLA_API_KEY!,
  authBaseUrl: "https://your-company.auth.aiola.ai"
});

const client = new AiolaClient({
  accessToken: result.accessToken,
  baseUrl: "https://your-company.api.aiola.ai"
});
```

## Error Handling

### Common Authentication Errors

#### **401 Unauthorized**

```json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired access token"
  }
}
```

**Solutions:**

* Verify token is included in Authorization header
* Check token format: `Bearer <token>`
* Generate a new access token

#### **403 Forbidden**

```json
{
  "error": {
    "code": "FORBIDDEN", 
    "message": "API key does not have required permissions"
  }
}
```

**Solutions:**

* Verify API key has correct permissions
* Check if API key is active and not revoked
* Contact support for permission adjustments

## FAQ

#### How long do access tokens last?

Access tokens typically last 30 minutes. The SDK handles token management internally, but you should implement refresh logic for long-running applications.

#### Can I use the same access token across multiple applications?

Yes, access tokens can be shared across applications, but consider security implications. For better isolation, generate separate tokens for different services.

#### What happens if my API key is compromised?

Immediately rotate your API key in the aiOla dashboard. All existing access tokens will become invalid, requiring new token generation.

#### Can I extend token lifetime?

Token lifetimes are fixed for security reasons. Implement automatic token refresh in your applications instead.

#### Do I need different API keys for different environments?

Yes, use separate API keys for development, staging, and production environments for better security and monitoring.

## Next Steps

* **STT Integration**: Learn how to implement [Speech-to-Text](/docs/pages/stt-sdk-guide) with authentication
* **TTS Integration**: Explore [Text-to-Speech](/docs/pages/tts-sdk-guide) implementation patterns
* **Streaming**: Set up [real-time streaming](/docs/pages/stt-streaming-guide) with proper authentication
* **Quickstart**: Follow our [Quickstart Guide](/docs/pages/quickstart) for a complete setup example

---

> **Info**
>
> **Need Help?** If you encounter issues with authentication, contact our support team.