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

# API Key Authentication for Evaluation Partners

API key authentication system for Tradovate evaluation partners. This guide covers the complete authentication flow using your provided API key to obtain and manage access tokens.

## Authentication Overview

Evaluation partners use API key authentication to obtain access tokens for secure communication with Tradovate services. Access tokens expire after **90 minutes** and should be refreshed every **85 minutes** to ensure uninterrupted service.

### Key Requirements

* **Store access tokens** to prevent overuse of the `getAccessToken` endpoint
* **Refresh tokens every 85 minutes** (they expire after 90 minutes)

## Implementation

### Authentication Implementation

First, create a `.env` file in your project root with your Tradovate credentials:

```bash title=".env"
# Tradovate API Configuration
TRADOVATE_API_URL=https://live-api.staging.ninjatrader.dev/v1
# Use https://live.tradovateapi.com/v1/auth/accesstokenrequest for production

# Your Tradovate Credentials
TRADOVATE_USERNAME=your_username_here
TRADOVATE_PASSWORD=your_password_here
TRADOVATE_APP_ID=your_app_id_here
TRADOVATE_DEVICE_ID=your_unique_device_id
TRADOVATE_APP_VERSION=1.0
TRADOVATE_SEC=your_api_secret_here
TRADOVATE_CID=0
```

Install the dotenv package to load environment variables:

```bash
npm install dotenv
```

**Security Best Practice**: Add `.env` to your `.gitignore` file to prevent committing sensitive credentials to version control:

```gitignore title=".gitignore"
.env
```

Now implement authentication using environment variables:

```typescript
import 'dotenv/config'; // Load environment variables

// --- Tradovate API Configuration from Environment Variables ---
const TRADOVATE_API_URL = process.env.TRADOVATE_API_URL || 'https://live-api.staging.ninjatrader.dev/v1';
const USERNAME = process.env.TRADOVATE_USERNAME;
const PASSWORD = process.env.TRADOVATE_PASSWORD;
const APP_ID = process.env.TRADOVATE_APP_ID;
const APP_VERSION = process.env.TRADOVATE_APP_VERSION || '1.0';
const SEC = process.env.TRADOVATE_SEC;
const CID = parseInt(process.env.TRADOVATE_CID || '0');

/**
 * Requests an access token from the Tradovate API.
 */
async function requestAccessToken() {
    console.log("--- Starting Tradovate Access Token Request ---");

    // Basic input validation - check for required environment variables
    if (!USERNAME || !PASSWORD || !APP_ID || !DEVICE_ID) {
        console.error("\nERROR: Missing required environment variables.");
        console.error("Please ensure your .env file contains:");
        console.error("- TRADOVATE_USERNAME");
        console.error("- TRADOVATE_PASSWORD");
        console.error("- TRADOVATE_APP_ID");
        console.error("- TRADOVATE_DEVICE_ID");
        process.exit(1);
    }

    const AUTH_ENDPOINT = `${TRADOVATE_API_URL}/auth/accesstokenrequest`;
    
    const authPayload = {
        name: USERNAME,
        password: PASSWORD,
        appId: APP_ID,
        appVersion: APP_VERSION,
        cid: CID,
        sec: SEC
    };

    try {
        console.log(`\nAttempting to authenticate to: ${AUTH_ENDPOINT}`);

        // 1. Send POST request to the authentication endpoint using Node's native fetch
        const response = await fetch(AUTH_ENDPOINT, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(authPayload)
        });

        // 2. Parse the JSON response body
        const data = await response.json();

        // 3. Check for successful response (HTTP status 2xx and presence of accessToken)
        if (response.ok && data.accessToken) {
            console.log("\n✅ SUCCESS: Access Token Retrieved.");
            console.log("-----------------------------------------");
            console.log(`Token: ${data.accessToken.substring(0, 8)}... (truncated for security)`);
            console.log(`Expiration Time: ${data.expirationTime}`);
            console.log(`User ID: ${data.userId}`);
            console.log("-----------------------------------------");
            return data; // Return the auth response for further use
        } else {
            // Handle API-specific errors (e.g., invalid credentials)
            console.error("\n❌ API ERROR: Failed to retrieve token.");
            console.error("Status:", response.status);
            if (data.errorText) {
                console.error("Details:", data.errorText, "-", data.message);
            } else {
                console.error("Raw Response:", JSON.stringify(data, null, 2));
            }
            throw new Error(`Authentication failed: ${data.errorText || 'Unknown error'}`);
        }

    } catch (error) {
        // Catch network errors, DNS failures, etc.
        console.error("\n❌ NETWORK ERROR: Could not connect to the API server.");
        console.error("Details:", error.message);
        throw error;
    }
}

// Execute the main function (standalone usage)
requestAccessToken()
    .then(() => {
        console.log("✅ Authentication completed successfully!");
        process.exit(0);
    })
    .catch((error) => {
        console.error("❌ Authentication failed:", error.message);
        process.exit(1);
    });
```

### Using the Access Token

Once you have an access token, you can make authenticated requests to the API. The access token must be send as a bearer token in the Authorization header for all HTTP requests. Here's how to verify your authentication by calling the `/auth/me` endpoint:

```typescript
/**
 * Demonstrates how to use the access token with the /auth/me endpoint
 */
async function getUserInfo(accessToken: string) {
    const ME_ENDPOINT = `${TRADOVATE_API_URL}/auth/me`;
    
    try {
        console.log("--- Fetching User Information ---");
        
        const response = await fetch(ME_ENDPOINT, {
            method: 'GET',
            headers: {
                'Authorization': `Bearer ${accessToken}`,
                'Content-Type': 'application/json'
            }
        });

        if (response.ok) {
            const userData = await response.json();
            console.log("\n✅ SUCCESS: User data retrieved.");
            console.log("-----------------------------------------");
            console.log(`User ID: ${userData.id}`);
            console.log(`Username: ${userData.name}`);
            console.log(`Email: ${userData.email || 'Not provided'}`);
            console.log("-----------------------------------------");
            return userData;
        } else {
            console.error("\n❌ ERROR: Failed to fetch user information.");
            console.error("Status:", response.status);
            
            const errorData = await response.json().catch(() => ({}));
            if (errorData.errorText) {
                console.error("Details:", errorData.errorText);
            }
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
    } catch (error) {
        console.error("\n❌ NETWORK ERROR: Could not fetch user information.");
        console.error("Details:", error.message);
        throw error;
    }
}

// Example usage combining both functions
async function authenticateAndGetUserInfo() {
    try {
        // First, get the access token
        const authResponse = await requestAccessToken();
        
        // Then use it to get user information
        if (authResponse && authResponse.accessToken) {
            await getUserInfo(authResponse.accessToken);
        }
    } catch (error) {
        console.error("Authentication flow failed:", error.message);
        process.exit(1);
    }
}
```

## WebSocket Integration

For WebSocket connections, authentication after connection is required. After authenticating the websocket connection, you do not need to send the access token with every request.

We will go over websockets in more detail in the [websocket tutorial section](/overview/core-concepts/web-sockets/connection-overview).

```typescript
ws.on('open', function open() {
  // Authenticate the WebSocket connection
  ws.send(JSON.stringify({
    request: 'auth',
    accessToken: accessToken
  }));
});
```

## Security Best Practices

### Store Access Tokens Securely

```typescript
// In production, use secure storage mechanisms
class SecureTokenStorage {
  private encryptionKey: string;

  constructor(encryptionKey: string) {
    this.encryptionKey = encryptionKey;
  }

  storeToken(token: string, userId: number, expiresAt: number): void {
    const data = JSON.stringify({ token, userId, expiresAt });
    const encrypted = this.encrypt(data);
    
    // Store in secure location (database, encrypted file, etc.)
    localStorage.setItem('tradovate_auth', encrypted);
  }

  getStoredToken(): { token: string; userId: number; expiresAt: number } | null {
    const encrypted = localStorage.getItem('tradovate_auth');
    if (!encrypted) return null;

    try {
      const decrypted = this.decrypt(encrypted);
      return JSON.parse(decrypted);
    } catch {
      return null;
    }
  }

  private encrypt(data: string): string {
    // Implement encryption logic
    return Buffer.from(data).toString('base64'); // Simplified example
  }

  private decrypt(encrypted: string): string {
    // Implement decryption logic  
    return Buffer.from(encrypted, 'base64').toString(); // Simplified example
  }
}
```

## Partner Authentication Summary

**For evaluation partners, follow these key authentication requirements:**

1. **API Key Only**: Use the API key provided by Tradovate for authentication
2. **Store Tokens**: Cache access tokens to prevent overuse of the authentication endpoint
3. **85-Minute Refresh**: Refresh tokens every 85 minutes (they expire after 90 minutes)
4. **Bearer Token**: All HTTP requests must be signed with your API key as a bearer token in the Authorization header

This authentication system provides secure, efficient access token management specifically designed for evaluation partners using API key authentication.