Authentication Guide
The Apala API uses a two-tier authentication system: API keys for initial authentication and JWT tokens for ongoing API requests.
Authentication Flow
API Key Exchange: Your API key is exchanged for JWT access and refresh tokens
Token Usage: All API requests use the JWT access token
Automatic Refresh: The SDK automatically refreshes tokens when they expire
Basic Authentication
from apala_client import ApalaClient
# Initialize with API key
client = ApalaClient(
api_key="IjU50unIfiSfO3txKLWpRDugelb9SGbsi6KShkLzeOM=",
base_url="https://your-phoenix-server.com"
)
# Authenticate and get JWT tokens
auth_response = client.authenticate()
print(f"Company: {auth_response['company_name']}")
print(f"Token expires in: {auth_response['expires_in']} seconds")
Environment Variables
For security, store credentials in environment variables:
# Set environment variables
export APALA_API_KEY="your-api-key-here"
export APALA_BASE_URL="https://your-server.com"
export APALA_COMPANY_GUID="your-company-uuid"
import os
from apala_client import ApalaClient
# Load from environment
client = ApalaClient(
api_key=os.getenv("APALA_API_KEY"),
base_url=os.getenv("APALA_BASE_URL")
)
Token Management
The SDK handles token lifecycle automatically:
- Automatic Refresh
Tokens are refreshed 60 seconds before expiration
- Manual Refresh
You can manually refresh if needed:
# Force token refresh refresh_response = client.refresh_access_token() print(f"New token expires in: {refresh_response['expires_in']} seconds")
- Token Inspection
Check current token status:
import time # Check if token is valid current_time = time.time() is_valid = client.access_token and current_time < (client.token_expires_at or 0) if not is_valid: print("Token expired or missing, re-authenticating...") client.authenticate()
Authentication Errors
Handle common authentication issues:
import requests
try:
auth_response = client.authenticate()
except requests.HTTPError as e:
if e.response.status_code == 401:
print("Invalid API key")
elif e.response.status_code == 403:
print("API key lacks necessary permissions")
elif e.response.status_code >= 500:
print("Server error - try again later")
else:
print(f"Authentication failed: {e.response.status_code}")
except requests.ConnectionError:
print("Cannot connect to server - check URL and network")
Secure API Key Storage
- Development
Use environment variables or config files (never commit to git):
# .env file (add to .gitignore) APALA_API_KEY=your-key-here APALA_BASE_URL=https://your-server.com # Load with python-dotenv from dotenv import load_dotenv load_dotenv()
- Production
Use secure secret management:
# AWS Secrets Manager example import boto3 import json def get_api_credentials(): client = boto3.client('secretsmanager') response = client.get_secret_value(SecretId='apala-api-credentials') secrets = json.loads(response['SecretString']) return secrets['api_key'], secrets['base_url'] api_key, base_url = get_api_credentials() client = ApalaClient(api_key=api_key, base_url=base_url)
Authentication Best Practices
- Security
Never hardcode API keys in source code
Use environment variables for local development
Use secret management services in production
Rotate API keys regularly
- Error Handling
Always handle authentication failures gracefully
Implement retry logic for temporary failures
Log authentication events for monitoring
- Performance
Reuse the same client instance across requests
Let the SDK handle token refresh automatically
Don’t authenticate more frequently than necessary
Production Authentication Pattern
Here’s a production-ready authentication pattern:
import os
import logging
import time
from contextlib import contextmanager
from apala_client import ApalaClient
import requests
logger = logging.getLogger(__name__)
class SecureApalaClient:
def __init__(self):
self.api_key = os.environ["APALA_API_KEY"]
self.base_url = os.environ["APALA_BASE_URL"]
self._client = None
self._last_auth_attempt = 0
self._auth_retry_delay = 300 # 5 minutes
@contextmanager
def get_authenticated_client(self):
"""Context manager providing authenticated client."""
try:
client = self._get_client()
yield client
finally:
if client:
client.close()
def _get_client(self):
"""Get or create authenticated client."""
current_time = time.time()
# Create new client if needed
if not self._client:
self._client = ApalaClient(
api_key=self.api_key,
base_url=self.base_url
)
# Check if we need to authenticate
needs_auth = (
not self._client.access_token or
current_time >= (self._client.token_expires_at or 0)
)
if needs_auth:
self._authenticate_with_retry()
return self._client
def _authenticate_with_retry(self):
"""Authenticate with exponential backoff retry."""
current_time = time.time()
# Prevent too frequent retry attempts
if current_time - self._last_auth_attempt < self._auth_retry_delay:
raise Exception("Authentication retry delay not met")
max_retries = 3
for attempt in range(max_retries):
try:
logger.info(f"Authentication attempt {attempt + 1}")
self._client.authenticate()
logger.info("Authentication successful")
self._last_auth_attempt = current_time
return
except requests.HTTPError as e:
logger.error(f"Auth attempt {attempt + 1} failed: {e.response.status_code}")
if e.response.status_code in [401, 403]:
# Don't retry auth errors
raise
if attempt < max_retries - 1:
time.sleep(2 ** attempt) # Exponential backoff
except requests.ConnectionError as e:
logger.error(f"Auth attempt {attempt + 1} connection failed: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
self._last_auth_attempt = current_time
raise Exception(f"Authentication failed after {max_retries} attempts")
# Usage
secure_client = SecureApalaClient()
with secure_client.get_authenticated_client() as client:
response = client.message_process(...)
Debugging Authentication
Enable debug logging to troubleshoot authentication issues:
import logging
import urllib3
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
urllib3.disable_warnings() # Optional: disable SSL warnings
client = ApalaClient(api_key="your-key", base_url="https://server.com")
try:
auth_response = client.authenticate()
print("Debug: Authentication successful")
except Exception as e:
print(f"Debug: Authentication failed - {e}")
This will show detailed HTTP request/response information to help diagnose authentication problems.