> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://partner.ninjatrader.com/connect/overview/quick-setup/auth-overview/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 **80 minutes**. Each token response includes an `expirationTime` field with the exact expiry time. Renew by calling [`renewAccessToken`](/api/rest-api-endpoints/authentication/renew-access-token) 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`** ```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 ``` > **Note** > > **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. **Renew Before Expiration**: Access tokens expire after 80 minutes; renew before the `expirationTime` in the token response by calling [`renewAccessToken`](/api/rest-api-endpoints/authentication/renew-access-token) 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.