Authentication¶
The FiveTwenty library provides secure, flexible authentication for OANDA's API. This guide covers obtaining API tokens and configuring authentication securely.
Getting Your API Token¶
To use the FiveTwenty library, you need an OANDA API access token:
- Practice Account: Sign up at OANDA (free practice accounts available)
- Live Account: Available to funded accounts at OANDA
Finding Your Token¶
- Log into your OANDA account
- Navigate to Manage API Access in your account settings
- Generate a new token or use an existing one
- Copy the token securely
Security
Never commit your API token to version control! The library provides secure configuration options to protect your credentials.
Authentication Methods¶
The FiveTwenty library supports three secure authentication approaches:
1. Direct Parameters¶
The most straightforward approach is to pass credentials directly to the client constructor. This example shows how to authenticate using environment variables for security:
import asyncio
import os
from dotenv import load_dotenv
from fivetwenty import AsyncClient, Environment
# Load environment variables from .env file
load_dotenv()
async def main() -> None:
"""
Tutorial: Basic OANDA API Authentication.
This example demonstrates how to connect to the OANDA API using the fivetwenty library.
You'll learn how to:
- Create an authenticated API client
- Retrieve account information
- Verify your connection is working
"""
# Step 1: Create the API client
# The AsyncClient manages your connection to OANDA's servers
# Using 'async with' ensures proper cleanup when done
async with AsyncClient(
# Your API token authenticates your requests (stored in .env file)
token=os.environ["FIVETWENTY_OANDA_TOKEN"],
# The account ID specifies which OANDA account to interact with
account_id=os.environ["FIVETWENTY_OANDA_ACCOUNT"],
# Use PRACTICE for learning/testing (never risk real money while learning!)
environment=Environment.PRACTICE,
) as client:
# Step 2: Test the connection by fetching your accounts
# This API call returns a list of all accounts you have access to
accounts = await client.accounts.get_accounts()
account_count = len(accounts)
# Step 3: Display the results
# If you see this message, your API credentials are working correctly!
print(f" Authentication successful - found {account_count} account(s)")
print(f"📋 Configuration: {client.config.summary()}")
# Step 4: Run the tutorial when this script is executed
# asyncio.run() is needed because we're using async/await for API calls
if __name__ == "__main__":
asyncio.run(main())
2. Configuration Objects¶
For reusable configurations and multi-account scenarios, use configuration objects. This approach is ideal when running multiple clients connected to different accounts:
from fivetwenty import AccountConfig, AsyncClient, Environment
# Step 1: Create reusable configuration object for structured credential management
# AccountConfig provides validation, security masking, and reusability across clients
config = AccountConfig(
token="your-api-token", # Replace with actual OANDA API token
account_id="your-account-id", # Replace with actual account identifier
environment=Environment.PRACTICE, # Practice environment for safe development
alias="development_account" # Optional alias for configuration identification
)
# Step 2: Initialize client using pre-configured settings
# Configuration objects enable consistent settings across multiple client instances
async with AsyncClient(config=config) as client:
# Step 3: Verify authentication by retrieving account information
# This confirms the configuration object contains valid credentials
accounts = await client.accounts.get_accounts()
account_count = len(accounts)
# Step 4: Display configuration summary with automatic credential masking
# Summary method protects sensitive information while showing configuration status
print(f"List Using configuration: {client.config.summary()}")
print(f"Success Successfully retrieved {account_count} account(s)")
print(f"Lock Token and account ID are automatically masked for security")
3. Environment Variables¶
The most secure and convenient approach uses environment variables for zero-config authentication. First, set up your environment:
# Set environment variables (in your shell etc).
export FIVETWENTY_OANDA_TOKEN="your-api-token"
export FIVETWENTY_OANDA_ACCOUNT="your-account-id"
export FIVETWENTY_OANDA_ENVIRONMENT="practice"
# Configuration is loaded automatically when these are set
Then create clients without explicitly passing credentials - the library automatically loads configuration from environment variables:
import asyncio # Needed for async/await operations (API calls run asynchronously)
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def main() -> None:
"""
Tutorial: Zero-Configuration Authentication
This example shows the simplest way to connect to OANDA - just set your
environment variables and the fivetwenty library handles the rest!
"""
# Import AsyncClient inside the function (can also import at top of file)
from fivetwenty import AsyncClient
# Step 1: Create the API client with zero configuration
# The AsyncClient automatically reads these environment variables:
# - FIVETWENTY_OANDA_TOKEN: Your API token for authentication
# - FIVETWENTY_OANDA_ACCOUNT: Your account ID
# - FIVETWENTY_OANDA_ENVIRONMENT: "practice" or "live"
# Using 'async with' ensures the connection is properly closed when done
async with AsyncClient() as client:
# Step 2: Test the connection by fetching your accounts
# This API call retrieves a list of all accounts you can access
# If this succeeds, your credentials are configured correctly!
accounts = await client.accounts.get_accounts()
account_count = len(accounts)
# Step 3: Display the results
# The config.summary() method shows your settings without exposing secrets
print(f" Auto-loaded configuration: {client.config.summary()}")
print(f" Authentication successful: {account_count} account(s) found")
print(" Ready for trading operations!")
# Step 4: Run the tutorial
# This is the standard Python idiom for executable scripts
# asyncio.run() is required because our main() function uses async/await
if __name__ == "__main__":
asyncio.run(main())
Secure Token Management¶
Environment Variables (Recommended)¶
Never hardcode tokens. Use environment variables:
Error Bad - Never do this:
Success Good - Use environment variables:
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Step 1: Safely retrieve API token from environment variables
# Environment variables keep secrets out of source code and version control
token = os.environ.get("FIVETWENTY_OANDA_TOKEN")
# Step 2: Validate that required credentials are available
# Early validation prevents runtime failures during authentication
if not token:
raise ValueError("FIVETWENTY_OANDA_TOKEN environment variable not set")
# Step 3: Confirm token loading with secure masking
# Display confirmation while protecting sensitive credential information
masked_token = '*' * min(8, len(token)) + '...' if len(token) > 8 else '*' * len(token)
print(f"Lock Token loaded from environment: {masked_token}")
print(f"Success Environment-based authentication configured successfully")
Using .env Files¶
For local development, install python-dotenv and create a .env file:
# .env file (add to .gitignore!)
FIVETWENTY_OANDA_TOKEN=your-practice-token
FIVETWENTY_OANDA_ACCOUNT=your-account-id
FIVETWENTY_OANDA_ENVIRONMENT=practice
FIVETWENTY_OANDA_ACCOUNT_ALIAS=development_account
import asyncio
async def main() -> None:
"""Demonstrate secure local development using .env file configuration."""
from dotenv import load_dotenv
from fivetwenty import AsyncClient
# Step 1: Load environment variables from .env file
# dotenv provides secure local development without hardcoding credentials
load_dotenv()
print("Config Environment variables loaded from .env file")
print("Folder .env file should be added to .gitignore for security")
# Step 2: Create client using automatically loaded environment variables
# AsyncClient seamlessly uses the variables loaded by dotenv
async with AsyncClient() as client:
# Step 3: Validate that .env configuration works correctly
# Account listing confirms successful authentication using .env credentials
accounts = await client.accounts.get_accounts()
account_count = len(accounts)
# Step 4: Confirm successful .env-based authentication
print(f"Success Authentication successful: {account_count} account(s) found")
print(f"Starting Local development environment configured properly")
# Step 5: Execute the .env-based authentication test
if __name__ == "__main__":
asyncio.run(main())
Secret Management Systems¶
For production deployments, you can use AWS Secrets Manager, HashiCorp Vault, Kubernetes Secrets, etc. to set environment variables as appropriate.
Multiple Account Configuration¶
FiveTwenty supports managing multiple OANDA accounts simultaneously - essential for hedging strategies, US broker compliance, or isolating different trading approaches.
Multi-Account Management
For detailed examples of multi-account setups including US broker hedging compliance, separate strategy accounts, and aggregate account monitoring, see Account Management Tutorial.
Security Features¶
Automatic Secret Masking¶
The library automatically protects sensitive information:
import os
from dotenv import load_dotenv
from fivetwenty import AccountConfig, Environment
from pydantic import SecretStr
# Load environment variables from .env file
load_dotenv()
# Step 1: Create configuration with automatic security masking
# AccountConfig automatically protects sensitive information from exposure
config = AccountConfig(
token=SecretStr(
os.environ["FIVETWENTY_OANDA_TOKEN"]
), # API token (automatically masked)
account_id=SecretStr(
os.environ["FIVETWENTY_OANDA_ACCOUNT"]
), # Account ID (automatically masked)
environment=Environment.PRACTICE, # Environment setting (visible)
alias="my_account", # Friendly alias (visible)
)
# Step 2: Demonstrate automatic secret masking in string representation
# repr() output masks sensitive credentials while showing configuration structure
config_repr = repr(config)
print(f"Lock Configuration representation: {config_repr}")
print(" Note: Token and account ID are automatically masked with '***'")
# Output: AccountConfig(alias='my_account', environment=practice, token=SecretStr('***'), account_id=SecretStr('***'))
# Step 3: Generate safe summary for logging and monitoring
# Summary method provides configuration info without exposing sensitive data
summary = config.summary()
print(f"Data Safe configuration summary: {summary}")
print(" Safe for logs, monitoring, and display purposes")
# Output: my_account (practice)
Configuration Validation¶
The library validates all configuration values:
from fivetwenty import AccountConfig, Environment
from pydantic import SecretStr, ValidationError
# Step 1: Demonstrate token validation (empty/whitespace tokens rejected)
# Configuration validation prevents common credential errors before runtime
try:
config = AccountConfig(
token=SecretStr(" "), # Empty/whitespace token - validation fails
account_id=SecretStr("123-456-789"), # Valid account ID format
environment=Environment.PRACTICE, # Valid environment
alias="my_account", # Valid alias
)
print(f"Error Unexpected success: {config}")
except ValidationError as e:
print("Success Empty token rejected (expected): Configuration validation working")
print(f" Error details: {e}")
# Step 2: Demonstrate alias validation (must follow naming rules)
# Alias validation ensures configuration identifiers follow proper conventions
try:
config = AccountConfig(
token=SecretStr("valid-token"), # Valid token format
account_id=SecretStr("valid-account"), # Valid account ID
environment=Environment.PRACTICE, # Valid environment
alias="123invalid", # Invalid alias - starts with number
)
print(f"Error Unexpected success: {config}")
except ValidationError as e:
print("Success Invalid alias rejected (expected): Alias validation working")
print(f" Error details: {e}")
print(" Note: Aliases must start with a letter, not a number")
Testing Authentication¶
Before deploying your application, it's important to verify that your authentication setup works correctly. You can test your configuration in two ways: validate the configuration structure without making API calls, or verify authentication by connecting to OANDA's servers.
Test Your Authentication Setup¶
This example demonstrates a complete authentication test that connects to OANDA's servers and retrieves your account information. The test verifies both your API credentials and network connectivity, displaying detailed account metrics including balance, open trades, and margin usage. Use this script to confirm your authentication setup before building trading applications.
import asyncio
import os
from dotenv import load_dotenv
from fivetwenty import AsyncClient, Environment
# Load environment variables from .env file
load_dotenv()
async def test_authentication() -> None:
"""Comprehensive authentication test with detailed account information and error handling."""
try:
# Step 1: Initialize client for authentication testing
# Practice environment provides safe testing without affecting live trading
async with AsyncClient(
token=os.environ["FIVETWENTY_OANDA_TOKEN"], # API token from environment
environment=Environment.PRACTICE, # Safe practice environment
) as client:
# Step 2: Validate authentication by requesting account data
# Account listing confirms successful API authentication and authorization
accounts = await client.accounts.get_accounts()
account_count = len(accounts)
# Step 3: Display authentication success with configuration summary
print("Success Authentication successful!")
print(f"Config Configuration: {client.config.summary()}")
print(f"Data Found {account_count} account(s):")
# Step 4: Display detailed account information for verification
# Account details help verify correct account access and trading capacity
for account in accounts:
account_info = f"{account.id}: {account.alias or 'No alias set'}"
balance_info = f"{account.balance} {account.currency}"
print(f" Business Account: {account_info}")
print(f" Balance Balance: {balance_info}")
print(f" Analysis Open Trades: {account.open_trade_count}")
print(f" Secure Margin Used: {account.margin_used} {account.currency}")
print(f"\nStarting Authentication test completed successfully")
except Exception as e:
# Step 5: Handle authentication failures with diagnostic information
# Detailed error handling helps identify configuration issues quickly
print(f"Error Authentication failed: {e}")
print(f"Search Troubleshooting steps:")
print(f" • Verify FIVETWENTY_OANDA_TOKEN environment variable is set")
print(f" • Check token validity in OANDA account management")
print(f" • Ensure network connectivity to OANDA servers")
print(f" • Confirm token matches selected environment (practice vs live)")
# Step 6: Execute the comprehensive authentication test
if __name__ == "__main__":
asyncio.run(test_authentication())
Security Considerations¶
Always follow these critical security guidelines:
- Never commit tokens to version control - Use environment variables
- Use separate tokens for different environments - Practice vs live
- Validate configurations before deployment - Catch issues early
Comprehensive Security Guide
For complete security best practices, token rotation strategies, and production deployment patterns, see Best Practices Guide.
Advanced Configuration
For environment-specific settings, organizational patterns, and performance optimization, see Configuration Guide.
Troubleshooting¶
If you encounter authentication issues, this section provides quick solutions for the most common problems.
Quick Fixes¶
Missing Environment Variables
export FIVETWENTY_OANDA_TOKEN="your-api-token"
export FIVETWENTY_OANDA_ACCOUNT="your-account-id"
export FIVETWENTY_OANDA_ENVIRONMENT="practice"
Invalid Token Format
import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Step 1: Validate token format and availability
# Token validation prevents authentication failures before API calls
# Step 2: Safely retrieve and clean token from environment
# Strip whitespace to handle common configuration errors
token = os.environ.get("FIVETWENTY_OANDA_TOKEN", "").strip()
# Step 3: Validate token presence and basic format
# Early validation catches configuration issues before runtime
if not token:
print("Error Token is empty or missing")
print(" Set FIVETWENTY_OANDA_TOKEN environment variable")
else:
# Step 4: Display token confirmation with security masking
# Show partial token for verification while protecting sensitive data
masked_token = token[:8] + "..." if len(token) > 8 else "*" * len(token)
print(f"Success Token loaded: {masked_token}")
print(f"Ruler Token length: {len(token)} characters")
print("Lock Token format appears valid")
Environment Mismatch
import os
from dotenv import load_dotenv
from fivetwenty import AsyncClient, Environment
# Load environment variables from .env file
load_dotenv()
# PROBLEM: Environment Mismatch Troubleshooting
# This example shows how to avoid a common mistake - using the wrong token
# with the wrong environment, which causes authentication failures.
# Step 1: Identify which token type you have
# OANDA tokens are environment-specific: practice tokens only work with practice,
# and live tokens only work with live environments
token = os.environ["FIVETWENTY_OANDA_TOKEN"]
account_id = os.environ.get("FIVETWENTY_OANDA_ACCOUNT")
# Step 2: Match your token to the correct environment
# CORRECT: Using practice token with practice environment
correct_client = AsyncClient(
token=token,
account_id=account_id,
environment=Environment.PRACTICE, # Matches practice token
)
print(" CORRECT: Practice token paired with PRACTICE environment")
print(f" Configuration: {correct_client.config.summary()}")
# WRONG: Don't mix token types with environments
# This would fail authentication:
# wrong_client = AsyncClient(
# token=token, # Practice token
# environment=Environment.LIVE, # Wrong! This expects a live token
# )
# Result: Authentication error - token doesn't match environment
# Step 3: Solution for multiple environments
# Keep separate environment variables for practice vs live tokens:
# .env file should have:
# FIVETWENTY_PRACTICE_TOKEN=your-practice-token
# FIVETWENTY_LIVE_TOKEN=your-live-token
# Then use them explicitly:
# practice_client = AsyncClient(
# token=os.environ["FIVETWENTY_PRACTICE_TOKEN"],
# environment=Environment.PRACTICE
# )
# live_client = AsyncClient(
# token=os.environ["FIVETWENTY_LIVE_TOKEN"],
# environment=Environment.LIVE
# )
print("\n Always match token type to environment:")
print(" • Practice tokens Environment.PRACTICE")
print(" • Live tokens Environment.LIVE")
Comprehensive Troubleshooting
For detailed authentication troubleshooting, debugging tools, network issues, SSL problems, and complete error diagnostics, see Connection Failure Handling Guide.
Summary¶
You now have a secure, flexible authentication setup for FiveTwenty. The SDK supports multiple authentication methods from direct parameters to environment variables, with automatic secret masking and comprehensive validation. Whether you're using a single account for development or multiple accounts for complex trading strategies, the configuration system scales to meet your needs while maintaining security best practices.
Next Steps¶
Now that authentication is configured:
- Learn about environments to understand practice vs live trading
- Make your first trade to test your setup
- Review configuration options for advanced use cases
- Check error handling for production readiness