Skip to main content

Reusable OAuth 2.0 adapters for multi-tenant SaaS applications

Project description

netrun-oauth

Reusable OAuth 2.0 adapters for multi-tenant SaaS applications. Extracted from Intirkast's production OAuth integration layer.

Features

  • Platform-Agnostic OAuth Adapters: Unified interface for 12+ OAuth platforms
  • Token Encryption: AES-256-GCM encryption via Fernet for secure token storage
  • Azure Integration: Native Azure Key Vault support for production deployments
  • Adapter Factory: Dynamic adapter creation with automatic credential injection
  • Multi-Tenant Ready: Designed for SaaS applications with tenant isolation
  • SDLC v2.2 Compliant: Security placeholders, comprehensive error handling, type hints

Supported Platforms

  • Microsoft (Azure AD, Office 365, Microsoft Graph)
  • Google (Workspace, Gmail, Calendar, Drive)
  • Salesforce
  • HubSpot
  • QuickBooks
  • Xero
  • Meta (Facebook, Instagram)
  • Mailchimp
  • Slack
  • Zoom
  • DocuSign
  • Dropbox

Installation

# Basic installation
pip install netrun-oauth

# With Azure Key Vault support
pip install netrun-oauth[azure]

# With development tools
pip install netrun-oauth[dev]

# Everything
pip install netrun-oauth[all]

Quick Start

Basic OAuth Flow

from netrun_oauth import OAuthAdapterFactory

# Create adapter (auto-resolves credentials from environment)
adapter = OAuthAdapterFactory.create("microsoft")

# Generate authorization URL
auth_url = await adapter.get_authorization_url(
    state="random_state_token",
    redirect_uri="https://app.example.com/oauth/callback"
)

# Exchange authorization code for token
token_data = await adapter.exchange_code_for_token(
    code="authorization_code_from_callback",
    redirect_uri="https://app.example.com/oauth/callback"
)

print(token_data.access_token)  # Access token
print(token_data.refresh_token)  # Refresh token
print(token_data.expires_at)  # Expiration datetime

Token Encryption

from netrun_oauth import TokenEncryptionService

# Initialize encryption service (auto-resolves key from environment/Azure Key Vault)
encryption = TokenEncryptionService()

# Encrypt token before storing in database
encrypted_token = encryption.encrypt_token(token_data.access_token)

# Decrypt token when needed
decrypted_token = encryption.decrypt_token(encrypted_token)

Explicit Credentials

# Provide credentials explicitly (bypasses auto-resolution)
adapter = OAuthAdapterFactory.create(
    "google",
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET"
)

Configuration

Environment Variables

Set platform-specific credentials:

# Microsoft
export MICROSOFT_CLIENT_ID="your_microsoft_client_id"
export MICROSOFT_CLIENT_SECRET="your_microsoft_client_secret"

# Google
export GOOGLE_CLIENT_ID="your_google_client_id"
export GOOGLE_CLIENT_SECRET="your_google_client_secret"

# Token encryption key (32-byte base64-encoded Fernet key)
export OAUTH_TOKEN_ENCRYPTION_KEY="your_fernet_key"

Generate encryption key:

from netrun_oauth import TokenEncryptionService

key = TokenEncryptionService.generate_key()
print(f"OAUTH_TOKEN_ENCRYPTION_KEY={key}")

Azure Key Vault (Production)

For production deployments, store credentials in Azure Key Vault:

# Set Key Vault URL
export AZURE_KEY_VAULT_URL="https://your-vault.vault.azure.net/"

# Store secrets in Key Vault (use Azure CLI or Portal)
az keyvault secret set --vault-name your-vault --name microsoft-client-id --value "..."
az keyvault secret set --vault-name your-vault --name microsoft-client-secret --value "..."
az keyvault secret set --vault-name your-vault --name oauth-token-encryption-key --value "..."

The adapter factory will automatically fetch credentials from Key Vault using DefaultAzureCredential.

Advanced Usage

Refresh Tokens

# Refresh expired access token
new_token_data = await adapter.refresh_token(refresh_token)

Revoke Tokens

# Revoke access token (disconnect account)
success = await adapter.revoke_token(access_token)

User Profile

# Fetch user profile information
profile = await adapter.get_user_profile(access_token)
print(profile["display_name"])
print(profile["email"])

Custom Adapters

from netrun_oauth import BaseOAuthAdapter, OAuthAdapterFactory

class CustomAdapter(BaseOAuthAdapter):
    async def get_authorization_url(self, state, redirect_uri, scopes=None):
        # Implementation
        pass

    # ... implement other abstract methods

# Register custom adapter
OAuthAdapterFactory.register_adapter("custom_platform", CustomAdapter)

# Use custom adapter
adapter = OAuthAdapterFactory.create("custom_platform")

Security Best Practices

Production Deployment

  1. Use Azure Key Vault: Store all credentials in Azure Key Vault, never in environment variables or code
  2. Enable Managed Identity: Use Azure Managed Identity for Key Vault access (no credentials needed)
  3. Rotate Keys: Implement key rotation for token encryption using rotate_encryption()
  4. Audit Logging: Log all OAuth operations for compliance and security monitoring
  5. HTTPS Only: Always use HTTPS for redirect URIs and API calls

Placeholder Format

For development/testing, use placeholder format:

client_id = "{{MICROSOFT_CLIENT_ID}}"
client_secret = "{{MICROSOFT_CLIENT_SECRET}}"

This prevents accidental credential leakage in version control.

Testing

# Run tests
pytest

# Run tests with coverage
pytest --cov=netrun_oauth --cov-report=html

# Run specific test
pytest tests/test_factory.py::test_factory_create_microsoft

Architecture

Adapter Pattern

Each platform adapter inherits from BaseOAuthAdapter and implements:

  • get_authorization_url() - Generate OAuth authorization URL
  • exchange_code_for_token() - Exchange authorization code for access token
  • refresh_token() - Refresh expired access token
  • revoke_token() - Revoke access token
  • post_text(), post_image(), post_video() - Platform-specific posting (optional)
  • get_user_profile() - Fetch user profile (optional)

Factory Pattern

OAuthAdapterFactory provides:

  • Dynamic adapter creation by platform name
  • Automatic credential injection (Key Vault → Environment → Placeholders)
  • Custom adapter registration
  • Platform enumeration

Token Encryption

TokenEncryptionService uses:

  • Fernet: Symmetric encryption with AES-256-GCM
  • Timestamps: Built-in expiration for key rotation
  • Authentication: HMAC prevents tampering
  • Key Resolution: Auto-loads from Key Vault or environment

API Reference

OAuthAdapterFactory

OAuthAdapterFactory.create(platform: str, client_id: str = None, client_secret: str = None, **kwargs) -> BaseOAuthAdapter
OAuthAdapterFactory.list_platforms() -> List[str]
OAuthAdapterFactory.register_adapter(platform: str, adapter_class: type) -> None

BaseOAuthAdapter

async get_authorization_url(state: str, redirect_uri: str, scopes: list = None) -> str
async exchange_code_for_token(code: str, redirect_uri: str, code_verifier: str = None, state: str = None) -> TokenData
async refresh_token(refresh_token: str) -> TokenData
async revoke_token(access_token: str) -> bool
async post_text(access_token: str, content: str, **kwargs) -> PostResult
async post_image(access_token: str, content: str, image_url: str, **kwargs) -> PostResult
async post_video(access_token: str, content: str, video_url: str, **kwargs) -> PostResult
async get_user_profile(access_token: str) -> Dict[str, Any]

TokenEncryptionService

__init__(encryption_key: str = None)
encrypt_token(token: str) -> str
decrypt_token(encrypted_token: str) -> str
rotate_encryption(old_encrypted_token: str, new_key: str) -> str
is_initialized() -> bool
@staticmethod generate_key() -> str

Data Classes

@dataclass
class TokenData:
    access_token: str
    refresh_token: Optional[str] = None
    expires_at: Optional[datetime] = None
    token_type: str = "Bearer"
    scope: Optional[str] = None

@dataclass
class PostResult:
    success: bool
    platform: str
    post_id: Optional[str] = None
    post_url: Optional[str] = None
    error_message: Optional[str] = None
    retry_after_seconds: Optional[int] = None

Contributing

Contributions welcome! Please follow:

  1. Fork repository
  2. Create feature branch (git checkout -b feature/new-adapter)
  3. Implement adapter following BaseOAuthAdapter interface
  4. Add comprehensive tests (target 80%+ coverage)
  5. Update README with new platform
  6. Submit pull request

License

MIT License - see LICENSE file for details

Credits

Extracted from Intirkast production OAuth integration layer.

Developed by Netrun Systems - Cloud Infrastructure & Multi-Tenant SaaS Solutions.

Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

netrun_oauth-2.0.0.tar.gz (29.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

netrun_oauth-2.0.0-py3-none-any.whl (46.4 kB view details)

Uploaded Python 3

File details

Details for the file netrun_oauth-2.0.0.tar.gz.

File metadata

  • Download URL: netrun_oauth-2.0.0.tar.gz
  • Upload date:
  • Size: 29.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for netrun_oauth-2.0.0.tar.gz
Algorithm Hash digest
SHA256 53b256953031260e8c5309841b1fd7ea599b2099c9af251a88e86295ff27685d
MD5 6c1935fe0a5e7ad028e1d28347588ac3
BLAKE2b-256 9099f29ae55d08b5ca1af8d38220f80259e6de205886cd73d731efc3daf94aa0

See more details on using hashes here.

File details

Details for the file netrun_oauth-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: netrun_oauth-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 46.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for netrun_oauth-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d310de8ff793e914a7482d2c323551774e8a53d783b1d04df415542ee2a8a8fa
MD5 6e5aa68edf401dbf87ca31ce0bc2366f
BLAKE2b-256 6fb1ef51d686889194d37ae6b00398b0699d96308be9a7ea1cae3344b6bba02d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page