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 80 minutes. Each token response includes an expirationTime field with the exact expiry time. Renew by calling renewAccessToken with your current token before it expires.

Key Requirements

  • Store access tokens to prevent overuse of the accessTokenRequest endpoint
  • Renew tokens before they expire (80 minutes), using the expirationTime field from the token response for the exact expiry time

Implementation

Authentication Implementation

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

.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:

npm install dotenv

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

.gitignore
.env

Now implement authentication using environment variables:

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:

/**
* 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.

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

Security Best Practices

Store Access Tokens Securely

// 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. Renew Before Expiration: Access tokens expire after 80 minutes; renew before the expirationTime in the token response by calling renewAccessToken
  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.