> ## Documentation Index
> Fetch the complete documentation index at: https://docs.animusai.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication Setup

> Protect your API keys with a secure token provider pattern that keeps credentials safely on your backend server. Seamless authentication for frontend applications without compromising security.

## Security Architecture

### Why Token Provider?

Your organization's API key **never** touches the browser for security reasons:

* **API Key Protection**: Your Animus API key stays secure on your backend
* **User Authentication**: You control who can access your AI services
* **Token Expiration**: JWT tokens automatically expire for enhanced security
* **Audit Trail**: Track usage through your own authentication system

### Authentication Flow

```mermaid theme={null}
sequenceDiagram
    participant Browser as Browser App
    participant Backend as Your Backend
    participant Animus as Animus Auth Service
    
    Browser->>Backend: Request token (with user auth)
    Backend->>Backend: Validate user
    Backend->>Animus: POST /auth/generate-token
    Note over Backend,Animus: Headers: { apikey: "your_animus_key" }
    Animus->>Backend: JWT token
    Backend->>Browser: { accessToken: "jwt..." }
    Browser->>Browser: Store token & use for API calls
```

## Backend Implementation

### Basic Token Provider Endpoint

Here's how to implement a secure token provider endpoint in different backend frameworks:

<CodeGroup>
  ```javascript Node.js/Express theme={null}
  // server.js
  const express = require('express');
  const cors = require('cors');
  const app = express();

  app.use(cors());
  app.use(express.json());

  // Your Animus API key (keep this secure!)
  const ANIMUS_API_KEY = process.env.ANIMUS_API_KEY;

  app.post('/api/get-animus-token', async (req, res) => {
    try {
      // 1. Authenticate your user (implement your own logic)
      const userToken = req.headers.authorization;
      if (!userToken || !isValidUserToken(userToken)) {
        return res.status(401).json({ error: 'Unauthorized' });
      }

      // 2. Call Animus Auth Service
      const response = await fetch('https://api.animusai.co/auth/generate-token', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'apikey': ANIMUS_API_KEY
        }
      });

      if (!response.ok) {
        throw new Error(`Animus auth failed: ${response.status}`);
      }

      const data = await response.json();

      // 3. Return only the JWT token
      res.json({
        accessToken: data.accessToken
      });

    } catch (error) {
      console.error('Token generation error:', error);
      res.status(500).json({ error: 'Failed to generate token' });
    }
  });

  // Your user authentication logic
  function isValidUserToken(token) {
    // Implement your authentication logic here
    // This could check JWT tokens, session cookies, API keys, etc.
    return token === 'Bearer valid-user-token'; // Simplified example
  }

  app.listen(3001, () => {
    console.log('Token provider server running on port 3001');
  });
  ```

  ```python Python/Flask theme={null}
  from flask import Flask, request, jsonify
  from flask_cors import CORS
  import requests
  import os

  app = Flask(__name__)
  CORS(app)

  ANIMUS_API_KEY = os.getenv('ANIMUS_API_KEY')

  @app.route('/api/get-animus-token', methods=['POST'])
  def get_animus_token():
      try:
          # 1. Authenticate your user
          auth_header = request.headers.get('Authorization')
          if not auth_header or not is_valid_user_token(auth_header):
              return jsonify({'error': 'Unauthorized'}), 401

          # 2. Call Animus Auth Service
          response = requests.post(
              'https://api.animusai.co/auth/generate-token',
              headers={
                  'Content-Type': 'application/json',
                  'apikey': ANIMUS_API_KEY
              }
          )

          if not response.ok:
              raise Exception(f'Animus auth failed: {response.status_code}')

          data = response.json()

          # 3. Return only the JWT token
          return jsonify({
              'accessToken': data['accessToken']
          })

      except Exception as error:
          print(f'Token generation error: {error}')
          return jsonify({'error': 'Failed to generate token'}), 500

  def is_valid_user_token(token):
      # Implement your authentication logic here
      return token == 'Bearer valid-user-token'  # Simplified example

  if __name__ == '__main__':
      app.run(port=3001, debug=True)
  ```

  ```typescript Next.js API Route theme={null}
  // pages/api/get-animus-token.ts (or app/api/get-animus-token/route.ts for App Router)
  import { NextApiRequest, NextApiResponse } from 'next';

  export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method !== 'POST') {
      return res.status(405).json({ error: 'Method not allowed' });
    }

    try {
      // 1. Authenticate your user
      const authHeader = req.headers.authorization;
      if (!authHeader || !isValidUserToken(authHeader)) {
        return res.status(401).json({ error: 'Unauthorized' });
      }

      // 2. Call Animus Auth Service
      const response = await fetch('https://api.animusai.co/auth/generate-token', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'apikey': process.env.ANIMUS_API_KEY!
        }
      });

      if (!response.ok) {
        throw new Error(`Animus auth failed: ${response.status}`);
      }

      const data = await response.json();

      // 3. Return only the JWT token
      res.json({
        accessToken: data.accessToken
      });

    } catch (error) {
      console.error('Token generation error:', error);
      res.status(500).json({ error: 'Failed to generate token' });
    }
  }

  function isValidUserToken(token: string): boolean {
    // Implement your authentication logic here
    return token === 'Bearer valid-user-token'; // Simplified example
  }
  ```

  ```go Go/Gin theme={null}
  package main

  import (
      "bytes"
      "encoding/json"
      "fmt"
      "net/http"
      "os"

      "github.com/gin-contrib/cors"
      "github.com/gin-gonic/gin"
  )

  type TokenResponse struct {
      AccessToken string `json:"accessToken"`
  }

  type ErrorResponse struct {
      Error string `json:"error"`
  }

  func main() {
      r := gin.Default()
      r.Use(cors.Default())

      r.POST("/api/get-animus-token", getAnimusToken)
      r.Run(":3001")
  }

  func getAnimusToken(c *gin.Context) {
      // 1. Authenticate your user
      authHeader := c.GetHeader("Authorization")
      if authHeader == "" || !isValidUserToken(authHeader) {
          c.JSON(http.StatusUnauthorized, ErrorResponse{Error: "Unauthorized"})
          return
      }

      // 2. Call Animus Auth Service
      animusAPIKey := os.Getenv("ANIMUS_API_KEY")
      
      req, err := http.NewRequest("POST", "https://api.animusai.co/auth/generate-token", bytes.NewBuffer([]byte("{}")))
      if err != nil {
          c.JSON(http.StatusInternalServerError, ErrorResponse{Error: "Failed to create request"})
          return
      }

      req.Header.Set("Content-Type", "application/json")
      req.Header.Set("apikey", animusAPIKey)

      client := &http.Client{}
      resp, err := client.Do(req)
      if err != nil {
          c.JSON(http.StatusInternalServerError, ErrorResponse{Error: "Failed to generate token"})
          return
      }
      defer resp.Body.Close()

      var tokenResp TokenResponse
      if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
          c.JSON(http.StatusInternalServerError, ErrorResponse{Error: "Failed to parse response"})
          return
      }

      // 3. Return only the JWT token
      c.JSON(http.StatusOK, tokenResp)
  }

  func isValidUserToken(token string) bool {
      // Implement your authentication logic here
      return token == "Bearer valid-user-token" // Simplified example
  }
  ```
</CodeGroup>

## Frontend Integration

### Basic SDK Configuration

Once your backend is set up, configure the SDK to use your token provider:

```typescript theme={null}
import { AnimusClient } from 'animus-client';

const client = new AnimusClient({
  tokenProviderUrl: 'https://your-backend.com/api/get-animus-token',
  chat: {
    model: 'vivian-llama3.1-70b-1.0-fp8',
    systemMessage: 'You are a helpful assistant.'
  }
});

// The SDK will automatically call your token provider when needed
client.chat.send("Hello!"); // Event-driven - listen for messageComplete event
```

### User Authentication Integration

The SDK doesn't have built-in user authentication features. Instead, you handle user authentication in your backend token provider endpoint. Here's the recommended pattern:

```typescript theme={null}
// Your backend handles user authentication
// The SDK only needs the token provider URL
const client = new AnimusClient({
  tokenProviderUrl: 'https://your-backend.com/api/get-animus-token',
  chat: {
    model: 'vivian-llama3.1-70b-1.0-fp8',
    systemMessage: 'You are a helpful assistant.'
  }
});

// Your backend endpoint should:
// 1. Validate the user's session/token
// 2. Only return Animus tokens for authenticated users
// 3. Return 401 for unauthenticated requests
```

### Managing User Sessions

Since the SDK doesn't handle user authentication directly, you'll need to manage user sessions at the application level:

```typescript theme={null}
class AuthenticatedApp {
  private client: AnimusClient | null = null;
  private userSession: string | null = null;

  constructor() {
    // Initialize without client
  }

  async login(userCredentials: any) {
    // Handle user login with your auth system
    this.userSession = await this.authenticateUser(userCredentials);
    
    // Create SDK client after successful login
    // Your backend will validate the session when SDK requests tokens
    this.client = new AnimusClient({
      tokenProviderUrl: 'https://your-backend.com/api/get-animus-token',
      chat: {
        model: 'vivian-llama3.1-70b-1.0-fp8',
        systemMessage: 'You are a helpful assistant.'
      }
    });
  }

  async sendMessage(message: string) {
    if (!this.client || !this.userSession) {
      throw new Error('User not authenticated');
    }
    // Use event-driven approach
    this.client.chat.send(message);
    // Listen for messageComplete event to get response
  }

  logout() {
    this.userSession = null;
    if (this.client) {
      this.client.clearAuthToken(); // Clear cached Animus token
    }
    this.client = null;
  }

  private async authenticateUser(credentials: any): Promise<string> {
    // Your user authentication logic here
    // Return session token/ID
    return 'user-session-token';
  }
}

// Usage
const app = new AuthenticatedApp();

// User login
await app.login({ username: 'user', password: 'pass' });
const response = await app.sendMessage("Hello!");

// User logout
app.logout();
```

## Advanced Authentication

### Custom Token Storage

Control where Animus tokens are stored in the browser:

<CodeGroup>
  ```typescript localStorage theme={null}
  const client = new AnimusClient({
    tokenProviderUrl: 'https://your-backend.com/api/get-animus-token',
    tokenStorage: 'localStorage', // Persists across browser sessions
    chat: {
      model: 'vivian-llama3.1-70b-1.0-fp8',
      systemMessage: 'You are a helpful assistant.'
    }
  });
  ```

  ```typescript sessionStorage theme={null}
  const client = new AnimusClient({
    tokenProviderUrl: 'https://your-backend.com/api/get-animus-token',
    tokenStorage: 'sessionStorage', // Default - cleared when tab closes
    chat: {
      model: 'vivian-llama3.1-70b-1.0-fp8',
      systemMessage: 'You are a helpful assistant.'
    }
  });
  ```
</CodeGroup>

### Token Refresh Handling

Token refresh happens automatically, but you can handle authentication errors:

```typescript theme={null}
import { AuthenticationError } from 'animus-client';

try {
  // Event-driven approach - no await needed
  client.chat.send("Hello!");
  
  // Or use completions() for direct API calls
  const response = await client.chat.completions({
    messages: [{ role: 'user', content: 'Hello!' }]
  });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Token might be expired or invalid
    // Your backend token provider may have rejected the request
    console.log('Authentication failed, redirecting to login...');
    redirectToLogin();
  }
}
```

### Manual Token Management

Clear the stored Animus token when needed:

```typescript theme={null}
// Clear stored Animus token (forces refresh on next request)
client.clearAuthToken();

// Next request will call your token provider again
client.chat.send("This will fetch a new token");
```

**Note**: The SDK doesn't provide methods to check if a token exists or inspect token details. Token management is handled automatically, and you only need to clear tokens when necessary (e.g., on user logout).

### CORS Configuration

Configure CORS properly for production:

<CodeGroup>
  ```javascript Express CORS theme={null}
  // Production CORS setup
  app.use(cors({
    origin: ['https://your-app.com', 'https://www.your-app.com'],
    credentials: true,
    methods: ['POST'],
    allowedHeaders: ['Content-Type', 'Authorization']
  }));
  ```

  ```python Flask CORS theme={null}
  from flask_cors import CORS

  # Production CORS setup
  CORS(app, 
       origins=['https://your-app.com', 'https://www.your-app.com'],
       supports_credentials=True,
       methods=['POST'],
       allow_headers=['Content-Type', 'Authorization'])
  ```

  ```typescript Next.js CORS theme={null}
  // next.config.js
  module.exports = {
    async headers() {
      return [
        {
          source: '/api/get-animus-token',
          headers: [
            {
              key: 'Access-Control-Allow-Origin',
              value: 'https://your-app.com',
            },
            {
              key: 'Access-Control-Allow-Methods',
              value: 'POST',
            },
            {
              key: 'Access-Control-Allow-Headers',
              value: 'Content-Type, Authorization',
            },
          ],
        },
      ];
    },
  };
  ```
</CodeGroup>

## Troubleshooting

### Common Issues

**Token Provider URL Not Found (404)**

```typescript theme={null}
// Ensure your backend endpoint is correct
const client = new AnimusClient({
  tokenProviderUrl: 'https://your-backend.com/api/get-animus-token', // Check this URL
});
```

**CORS Errors**

```javascript theme={null}
// Backend: Enable CORS for your frontend domain
app.use(cors({
  origin: 'https://your-frontend-domain.com'
}));
```

**Authentication Loops**

```typescript theme={null}
// Check that your backend returns the correct format
// Expected response: { "accessToken": "jwt_token_here" }
```

### Debug Mode

Enable debug logging to troubleshoot authentication issues:

<CodeGroup>
  ```javascript Node.js Debug theme={null}
  // Add debug logging to your token provider
  console.log('Token request received:', {
    headers: req.headers,
    body: req.body,
    timestamp: new Date().toISOString()
  });
  ```

  ```python Python Debug theme={null}
  import logging

  # Add debug logging to your token provider
  logging.info(f'Token request received: {request.headers}, {request.get_json()}, {datetime.now()}')
  ```

  ```typescript TypeScript Debug theme={null}
  // Add debug logging to your token provider
  console.log('Token request received:', {
    headers: req.headers,
    body: req.body,
    timestamp: new Date().toISOString()
  });
  ```
</CodeGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Chat Completions" icon="message" href="/sdk-features/chat-completions">
    Start building chat features with secure authentication
  </Card>

  <Card title="Media & Vision" icon="eye" href="/sdk-features/media-vision">
    Add vision capabilities to your authenticated app
  </Card>

  <Card title="Tool Calling" icon="wrench" href="/advanced-sdk/tool-calling">
    Implement function calling with proper authentication
  </Card>

  <Card title="Event System" icon="bolt" href="/advanced-sdk/event-system">
    Handle authentication events in your application
  </Card>
</CardGroup>
