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:

.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
1.env

Now implement authentication using environment variables:

1import 'dotenv/config'; // Load environment variables
2
3// --- Tradovate API Configuration from Environment Variables ---
4const TRADOVATE_API_URL = process.env.TRADOVATE_API_URL || 'https://live-api.staging.ninjatrader.dev/v1';
5const USERNAME = process.env.TRADOVATE_USERNAME;
6const PASSWORD = process.env.TRADOVATE_PASSWORD;
7const APP_ID = process.env.TRADOVATE_APP_ID;
8const APP_VERSION = process.env.TRADOVATE_APP_VERSION || '1.0';
9const SEC = process.env.TRADOVATE_SEC;
10const CID = parseInt(process.env.TRADOVATE_CID || '0');
11
12/**
13 * Requests an access token from the Tradovate API.
14 */
15async function requestAccessToken() {
16 console.log("--- Starting Tradovate Access Token Request ---");
17
18 // Basic input validation - check for required environment variables
19 if (!USERNAME || !PASSWORD || !APP_ID || !DEVICE_ID) {
20 console.error("\nERROR: Missing required environment variables.");
21 console.error("Please ensure your .env file contains:");
22 console.error("- TRADOVATE_USERNAME");
23 console.error("- TRADOVATE_PASSWORD");
24 console.error("- TRADOVATE_APP_ID");
25 console.error("- TRADOVATE_DEVICE_ID");
26 process.exit(1);
27 }
28
29 const AUTH_ENDPOINT = `${TRADOVATE_API_URL}/auth/accesstokenrequest`;
30
31 const authPayload = {
32 name: USERNAME,
33 password: PASSWORD,
34 appId: APP_ID,
35 appVersion: APP_VERSION,
36 cid: CID,
37 sec: SEC
38 };
39
40 try {
41 console.log(`\nAttempting to authenticate to: ${AUTH_ENDPOINT}`);
42
43 // 1. Send POST request to the authentication endpoint using Node's native fetch
44 const response = await fetch(AUTH_ENDPOINT, {
45 method: 'POST',
46 headers: {
47 'Content-Type': 'application/json',
48 },
49 body: JSON.stringify(authPayload)
50 });
51
52 // 2. Parse the JSON response body
53 const data = await response.json();
54
55 // 3. Check for successful response (HTTP status 2xx and presence of accessToken)
56 if (response.ok && data.accessToken) {
57 console.log("\n✅ SUCCESS: Access Token Retrieved.");
58 console.log("-----------------------------------------");
59 console.log(`Token: ${data.accessToken.substring(0, 8)}... (truncated for security)`);
60 console.log(`Expiration Time: ${data.expirationTime}`);
61 console.log(`User ID: ${data.userId}`);
62 console.log("-----------------------------------------");
63 return data; // Return the auth response for further use
64 } else {
65 // Handle API-specific errors (e.g., invalid credentials)
66 console.error("\n❌ API ERROR: Failed to retrieve token.");
67 console.error("Status:", response.status);
68 if (data.errorText) {
69 console.error("Details:", data.errorText, "-", data.message);
70 } else {
71 console.error("Raw Response:", JSON.stringify(data, null, 2));
72 }
73 throw new Error(`Authentication failed: ${data.errorText || 'Unknown error'}`);
74 }
75
76 } catch (error) {
77 // Catch network errors, DNS failures, etc.
78 console.error("\n❌ NETWORK ERROR: Could not connect to the API server.");
79 console.error("Details:", error.message);
80 throw error;
81 }
82}
83
84// Execute the main function (standalone usage)
85requestAccessToken()
86 .then(() => {
87 console.log("✅ Authentication completed successfully!");
88 process.exit(0);
89 })
90 .catch((error) => {
91 console.error("❌ Authentication failed:", error.message);
92 process.exit(1);
93 });

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:

1/**
2 * Demonstrates how to use the access token with the /auth/me endpoint
3 */
4async function getUserInfo(accessToken: string) {
5 const ME_ENDPOINT = `${TRADOVATE_API_URL}/auth/me`;
6
7 try {
8 console.log("--- Fetching User Information ---");
9
10 const response = await fetch(ME_ENDPOINT, {
11 method: 'GET',
12 headers: {
13 'Authorization': `Bearer ${accessToken}`,
14 'Content-Type': 'application/json'
15 }
16 });
17
18 if (response.ok) {
19 const userData = await response.json();
20 console.log("\n✅ SUCCESS: User data retrieved.");
21 console.log("-----------------------------------------");
22 console.log(`User ID: ${userData.id}`);
23 console.log(`Username: ${userData.name}`);
24 console.log(`Email: ${userData.email || 'Not provided'}`);
25 console.log("-----------------------------------------");
26 return userData;
27 } else {
28 console.error("\n❌ ERROR: Failed to fetch user information.");
29 console.error("Status:", response.status);
30
31 const errorData = await response.json().catch(() => ({}));
32 if (errorData.errorText) {
33 console.error("Details:", errorData.errorText);
34 }
35 throw new Error(`HTTP ${response.status}: ${response.statusText}`);
36 }
37 } catch (error) {
38 console.error("\n❌ NETWORK ERROR: Could not fetch user information.");
39 console.error("Details:", error.message);
40 throw error;
41 }
42}
43
44// Example usage combining both functions
45async function authenticateAndGetUserInfo() {
46 try {
47 // First, get the access token
48 const authResponse = await requestAccessToken();
49
50 // Then use it to get user information
51 if (authResponse && authResponse.accessToken) {
52 await getUserInfo(authResponse.accessToken);
53 }
54 } catch (error) {
55 console.error("Authentication flow failed:", error.message);
56 process.exit(1);
57 }
58}

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.

1ws.on('open', function open() {
2 // Authenticate the WebSocket connection
3 ws.send(JSON.stringify({
4 request: 'auth',
5 accessToken: accessToken
6 }));
7});

Security Best Practices

Store Access Tokens Securely

1// In production, use secure storage mechanisms
2class SecureTokenStorage {
3 private encryptionKey: string;
4
5 constructor(encryptionKey: string) {
6 this.encryptionKey = encryptionKey;
7 }
8
9 storeToken(token: string, userId: number, expiresAt: number): void {
10 const data = JSON.stringify({ token, userId, expiresAt });
11 const encrypted = this.encrypt(data);
12
13 // Store in secure location (database, encrypted file, etc.)
14 localStorage.setItem('tradovate_auth', encrypted);
15 }
16
17 getStoredToken(): { token: string; userId: number; expiresAt: number } | null {
18 const encrypted = localStorage.getItem('tradovate_auth');
19 if (!encrypted) return null;
20
21 try {
22 const decrypted = this.decrypt(encrypted);
23 return JSON.parse(decrypted);
24 } catch {
25 return null;
26 }
27 }
28
29 private encrypt(data: string): string {
30 // Implement encryption logic
31 return Buffer.from(data).toString('base64'); // Simplified example
32 }
33
34 private decrypt(encrypted: string): string {
35 // Implement decryption logic
36 return Buffer.from(encrypted, 'base64').toString(); // Simplified example
37 }
38}

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.