Master VBAPI's authentication system with comprehensive token management, security best practices, and multi-environment deployment strategies.
VBAPI uses a two-step authentication model designed for security and scalability:
- User Authentication — Exchange username/password credentials for an ID Token (JWT)
- Bearer Auth — Send the ID Token in the
Authorizationheader for all API requests
This guide covers advanced authentication patterns, token lifecycle management, and production security practices.
Required headers for every request:
x-api-key: YOUR_API_KEY
Authorization: Bearer <id_token>
vbasoftware-database: YOUR_DATABASE
User-Agent: <your-app-name> # requiredAlways include a clear User-Agent string. VBA uses it for:
- Request fingerprinting
- Debugging
- Identifying traffic patterns
- Issue triage via Support
Failing to set a User-Agent will result in a 403 Forbidden response.
- ID Tokens are valid for 24 hours
- Cache tokens locally to avoid unnecessary authentication calls
- Implement automatic refresh when tokens near expiration
import time
from datetime import datetime, timedelta
class VBAPITokenManager:
def __init__(self, username, password, api_key, client_id, client_code, database):
self.credentials = {
'username': username,
'password': password,
'api_key': api_key,
'client_id': client_id,
'client_code': client_code,
'database': database
}
self.token = None
self.token_expires = None
def get_valid_token(self):
"""Returns a valid token, refreshing if necessary"""
if self.token is None or self._is_token_expired():
self._refresh_token()
return self.token
def _is_token_expired(self):
"""Check if token expires in the next 5 minutes"""
if self.token_expires is None:
return True
return datetime.now() + timedelta(minutes=5) >= self.token_expires
def _refresh_token(self):
"""Refresh the authentication token"""
try:
self.token = self._get_id_token(
self.credentials['username'],
self.credentials['password']
)
# Tokens expire after 24 hours
self.token_expires = datetime.now() + timedelta(hours=23, minutes=55)
except Exception as e:
print(f"Token refresh failed: {e}")
raise
def _get_id_token(self, username, password):
"""Get ID token from VBAPI"""
import requests
import base64
url = "https://vbapi.vbasoftware.com/vbasoftware/user-authentication"
# Encode credentials: "username:password"
raw = f"{username}:{password}"
encoded = base64.b64encode(raw.encode()).decode()
headers = {
"x-api-key": self.credentials['api_key'],
"Authorization": f"Basic {encoded}",
"vbasoftware-client-id": self.credentials['client_id'],
"vbasoftware-client-code": self.credentials['client_code'],
"vbasoftware-database": self.credentials['database'],
"User-Agent": "VBAPITokenManager/1.0"
}
response = requests.post(url, headers=headers)
response.raise_for_status()
data = response.json()
return data["data"]["authenticationResult"]["idToken"]- Never hardcode credentials in source code
- Use environment variables or secure credential stores
- Rotate API keys regularly
- Store tokens in memory, not on disk
- Clear tokens from memory when application exits
- Use HTTPS for all API communications
- Never log or expose tokens in plain text
import threading
class SingletonTokenManager:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, 'initialized'):
self.token_manager = VBAPITokenManager(
username=os.getenv('VBAPI_USERNAME'),
password=os.getenv('VBAPI_PASSWORD'),
api_key=os.getenv('VBAPI_KEY'),
client_id=os.getenv('VBAPI_CLIENT_ID'),
client_code=os.getenv('VBAPI_CLIENT_CODE'),
database=os.getenv('VBAPI_DATABASE')
)
self.initialized = True
def get_token(self):
return self.token_manager.get_valid_token()
# Global token manager
token_manager = SingletonTokenManager()import asyncio
import aiohttp
import base64
class AsyncTokenManager:
def __init__(self, credentials):
self.credentials = credentials
self.token = None
self.token_expires = None
self._refresh_lock = asyncio.Lock()
async def get_valid_token(self):
"""Get a valid token, refreshing if necessary"""
if self.token is None or self._is_token_expired():
async with self._refresh_lock:
if self.token is None or self._is_token_expired():
await self._refresh_token()
return self.token
async def _refresh_token(self):
"""Asynchronously refresh the token"""
url = "https://vbapi.vbasoftware.com/vbasoftware/user-authentication"
raw = f"{self.credentials['username']}:{self.credentials['password']}"
encoded = base64.b64encode(raw.encode()).decode()
headers = {
"x-api-key": self.credentials['api_key'],
"Authorization": f"Basic {encoded}",
"vbasoftware-client-id": self.credentials['client_id'],
"vbasoftware-client-code": self.credentials['client_code'],
"vbasoftware-database": self.credentials['database'],
"User-Agent": "AsyncVBAPIClient/1.0"
}
async with aiohttp.ClientSession() as session:
async with session.post(url, headers=headers) as response:
response.raise_for_status()
data = await response.json()
self.token = data["data"]["authenticationResult"]["idToken"]
self.token_expires = datetime.now() + timedelta(hours=23, minutes=55)Cause: Missing or invalid User-Agent header
Solution: Always include a descriptive User-Agent header
headers = {
"User-Agent": "MyCompany-Integration/1.2.3",
# ... other headers
}Cause: Too frequent authentication calls
Solution: Implement proper token caching and reuse
# BAD: Authenticate for every request
def bad_api_call():
token = get_new_token() # Don't do this!
return make_request(token)
# GOOD: Reuse cached tokens
def good_api_call():
token = token_manager.get_valid_token() # Cached and reused
return make_request(token)Cause: Token has expired or is invalid
Solution: Implement automatic token refresh
def resilient_api_call(url, data):
"""API call with automatic token refresh"""
token = token_manager.get_valid_token()
try:
response = requests.post(url, headers={
'Authorization': f'Bearer {token}',
# ... other headers
}, json=data)
if response.status_code == 401:
# Token might be expired, refresh and retry once
token_manager.force_refresh()
token = token_manager.get_valid_token()
response = requests.post(url, headers={
'Authorization': f'Bearer {token}',
# ... other headers
}, json=data)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"API call failed: {e}")
raiseThis authentication guide provides the foundation for secure, scalable VBAPI integrations. Combine these patterns with proper error handling and monitoring.