Authentication¶
The Athena Client library supports multiple authentication methods to accommodate different use cases and security requirements. This guide covers setup and usage for each method.
Authentication Methods¶
OAuth Credential Helper (Recommended)¶
The OAuth credential helper is the recommended authentication method for production applications. It provides automatic token management, refresh capabilities, and robust error handling.
Features: * Automatic token acquisition and refresh * Thread-safe token caching * Comprehensive error handling * Configurable OAuth endpoints * Secure credential management
Setup:
from resolver_athena_client.client.channel import CredentialHelper, create_channel_with_credentials
# Create credential helper
credential_helper = CredentialHelper(
client_id="your-oauth-client-id",
client_secret="your-oauth-client-secret",
auth_url="https://crispthinking.auth0.com/oauth/token", # Optional
audience="crisp-athena-live" # Optional
)
# Create authenticated channel
channel = await create_channel_with_credentials(
host="your-athena-host",
credential_helper=credential_helper
)
Environment Variables:
Set these environment variables for OAuth authentication:
# Required
export OAUTH_CLIENT_ID="your-client-id"
export OAUTH_CLIENT_SECRET="your-client-secret"
export ATHENA_HOST="your-athena-host"
# Optional (defaults shown)
export OAUTH_AUTH_URL="https://crispthinking.auth0.com/oauth/token"
export OAUTH_AUDIENCE="crisp-athena-live"
Complete Example:
import asyncio
import os
from dotenv import load_dotenv
from resolver_athena_client.client.channel import CredentialHelper, create_channel_with_credentials
from resolver_athena_client.client.athena_client import AthenaClient
from resolver_athena_client.client.athena_options import AthenaOptions
async def main():
load_dotenv()
# OAuth configuration from environment
credential_helper = CredentialHelper(
client_id=os.getenv("OAUTH_CLIENT_ID"),
client_secret=os.getenv("OAUTH_CLIENT_SECRET"),
auth_url=os.getenv("OAUTH_AUTH_URL", "https://crispthinking.auth0.com/oauth/token"),
audience=os.getenv("OAUTH_AUDIENCE", "crisp-athena-live"),
)
# Test token acquisition
try:
token = await credential_helper.get_token()
print(f"Successfully acquired token (length: {len(token)})")
except Exception as e:
print(f"Failed to acquire OAuth token: {e}")
return
# Create authenticated channel
channel = await create_channel_with_credentials(
host=os.getenv("ATHENA_HOST"),
credential_helper=credential_helper
)
options = AthenaOptions(
host=os.getenv("ATHENA_HOST"),
deployment_id="your-deployment-id",
resize_images=True,
compress_images=True,
affiliate="your-affiliate",
)
async with AthenaClient(channel, options) as client:
# Your classification logic here
pass
asyncio.run(main())
Static Token Authentication¶
Static token authentication is suitable for simple use cases or when you already have a valid authentication token.
Features: * Simple setup with existing tokens * No automatic token refresh * Suitable for short-lived operations * Lower overhead for simple scripts
Setup:
from resolver_athena_client.client.channel import create_channel
# Use existing authentication token
channel = create_channel(
host="your-athena-host",
auth_token="your-static-token"
)
Complete Example:
import asyncio
from resolver_athena_client.client.channel import create_channel
from resolver_athena_client.client.athena_client import AthenaClient
from resolver_athena_client.client.athena_options import AthenaOptions
async def main():
# Create channel with static token
channel = create_channel(
host="your-athena-host",
auth_token="your-static-token"
)
options = AthenaOptions(
host="your-athena-host",
deployment_id="your-deployment-id",
resize_images=True,
compress_images=True,
affiliate="your-affiliate",
)
async with AthenaClient(channel, options) as client:
# Your classification logic here
pass
asyncio.run(main())
OAuth Configuration¶
Default Endpoints¶
The credential helper uses these default OAuth endpoints:
Auth URL:
https://crispthinking.auth0.com/oauth/token
Audience:
crisp-athena-live
These can be overridden when creating the CredentialHelper
.
Custom OAuth Endpoints¶
For custom OAuth providers or different environments:
credential_helper = CredentialHelper(
client_id="your-client-id",
client_secret="your-client-secret",
auth_url="https://your-custom-auth-provider.com/oauth/token",
audience="your-custom-audience"
)
Token Management¶
The credential helper automatically manages tokens:
Acquisition: Tokens are acquired on first use
Caching: Valid tokens are cached to avoid unnecessary requests
Refresh: Tokens are automatically refreshed before expiration
Thread Safety: Multiple concurrent requests safely share cached tokens
Security Best Practices¶
Environment Variables¶
Always use environment variables for sensitive credentials:
# .env file
OAUTH_CLIENT_ID=your-client-id
OAUTH_CLIENT_SECRET=your-client-secret
ATHENA_HOST=your-athena-host
Never hardcode credentials in your source code.
Credential Storage¶
For production applications:
Use secure credential storage (e.g., AWS Secrets Manager, Azure Key Vault)
Rotate credentials regularly
Use least-privilege access policies
Monitor credential usage
Development vs Production¶
Development:
# Development configuration
credential_helper = CredentialHelper(
client_id=os.getenv("DEV_OAUTH_CLIENT_ID"),
client_secret=os.getenv("DEV_OAUTH_CLIENT_SECRET"),
auth_url="https://dev-auth.example.com/oauth/token",
audience="dev-athena"
)
Production:
# Production configuration with secure credential retrieval
credential_helper = CredentialHelper(
client_id=get_secret("PROD_OAUTH_CLIENT_ID"),
client_secret=get_secret("PROD_OAUTH_CLIENT_SECRET"),
auth_url="https://auth.example.com/oauth/token",
audience="prod-athena"
)
Error Handling¶
OAuth Errors¶
Handle OAuth-specific errors gracefully:
from resolver_athena_client.client.exceptions import AuthenticationError
try:
token = await credential_helper.get_token()
except AuthenticationError as e:
logger.error(f"OAuth authentication failed: {e}")
# Handle authentication failure
except Exception as e:
logger.error(f"Unexpected error during authentication: {e}")
# Handle other errors
Connection Errors¶
Handle connection-related authentication issues:
try:
channel = await create_channel_with_credentials(host, credential_helper)
except ConnectionError as e:
logger.error(f"Failed to connect to Athena service: {e}")
# Handle connection failure
except AuthenticationError as e:
logger.error(f"Authentication failed: {e}")
# Handle authentication failure
Token Refresh Errors¶
The credential helper automatically handles token refresh, but you can monitor for issues:
import logging
# Enable debug logging to see token refresh activity
logging.getLogger("athena_client.client.channel").setLevel(logging.DEBUG)
async with AthenaClient(channel, options) as client:
# Long-running operations will automatically refresh tokens as needed
pass
Troubleshooting¶
Common Authentication Issues¶
- “Invalid client credentials”:
Verify
OAUTH_CLIENT_ID
andOAUTH_CLIENT_SECRET
are correctCheck that credentials haven’t been revoked
Ensure you’re using the correct auth URL
- “Invalid audience”:
Verify the audience parameter matches your OAuth configuration
Check with your OAuth provider for the correct audience value
- “Token expired”:
The credential helper should automatically refresh tokens
If this persists, check your OAuth provider’s token lifetime settings
- Connection timeouts:
Verify the
ATHENA_HOST
is correct and accessibleCheck network connectivity
Ensure the service is running and accepting connections
Debugging Authentication¶
Enable debug logging to troubleshoot authentication issues:
import logging
# Enable debug logging for authentication
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("athena_client.client.channel")
logger.setLevel(logging.DEBUG)
# Your authentication code here
Testing Authentication¶
Test your authentication setup:
async def test_authentication():
"""Test OAuth authentication without full client setup."""
try:
credential_helper = CredentialHelper(
client_id=os.getenv("OAUTH_CLIENT_ID"),
client_secret=os.getenv("OAUTH_CLIENT_SECRET"),
)
token = await credential_helper.get_token()
print(f"✓ Authentication successful (token length: {len(token)})")
return True
except Exception as e:
print(f"✗ Authentication failed: {e}")
return False
# Run the test
success = await test_authentication()
Migration Guide¶
From Static Tokens to OAuth¶
If you’re currently using static token authentication and want to migrate to OAuth:
Obtain OAuth credentials from your OAuth provider
Update your environment variables:
# Remove static token # ATHENA_TOKEN=your-static-token # Add OAuth credentials OAUTH_CLIENT_ID=your-client-id OAUTH_CLIENT_SECRET=your-client-secret
Update your code:
# Old static token approach # channel = create_channel(host=host, auth_token=token) # New OAuth approach credential_helper = CredentialHelper( client_id=os.getenv("OAUTH_CLIENT_ID"), client_secret=os.getenv("OAUTH_CLIENT_SECRET"), ) channel = await create_channel_with_credentials(host, credential_helper)
From Manual Token Management¶
If you were manually managing OAuth tokens:
Remove manual token logic
Use the credential helper for automatic management
Remove token refresh code - it’s handled automatically
Best Practices Summary¶
Use OAuth credential helper for production applications
Store credentials securely using environment variables or secret management
Never hardcode credentials in source code
Handle authentication errors gracefully
Monitor authentication for security and operational issues
Use different credentials for development and production
Test authentication setup before deploying
Enable debug logging when troubleshooting
For more information, see:
Examples for complete authentication examples
Client Interface for detailed API documentation
Installation Guide for setup instructions