Skip to main content

netrun-cors

Enterprise CORS middleware presets for FastAPI applications.

Overview

netrun-cors provides standardized, production-ready CORS configurations for FastAPI applications. Instead of manually configuring CORS middleware for each project, use battle-tested presets that follow OWASP security best practices.

Key Features:

  • 4 preset configurations: development, staging, production, oauth
  • OWASP compliance validation (prevents wildcard + credentials vulnerability)
  • OAuth platform support (Google, Twitter, LinkedIn, Facebook, TikTok, Instagram, Pinterest, Threads)
  • Azure Container Apps integration
  • Type-safe configuration with Pydantic
  • Comprehensive test coverage (90%+)

Installation

pip install netrun-cors

Or with Poetry:

poetry add netrun-cors

Quick Start

Development (Local Development)

Permissive CORS for rapid iteration on localhost:

from fastapi import FastAPI
from netrun_cors import CORSPreset

app = FastAPI()
app.add_middleware(CORSPreset.development())

Configuration:

  • Origins: localhost:3000, localhost:5173, 127.0.0.1:3000 (HTTP)
  • Credentials: Enabled
  • Methods: All (*)
  • Headers: All (*)
  • Max Age: 600s (10 minutes)

Production (Explicit Whitelist)

Strict origin whitelisting for production deployments:

from fastapi import FastAPI
from netrun_cors import CORSPreset

app = FastAPI()
app.add_middleware(
    CORSPreset.production(
        origins=[
            "https://app.example.com",
            "https://www.example.com"
        ]
    )
)

Configuration:

  • Origins: Explicit whitelist (HTTPS recommended)
  • Credentials: Enabled
  • Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH
  • Headers: Authorization, Content-Type, Accept, X-Request-ID
  • Expose Headers: X-Request-ID
  • Max Age: 3600s (1 hour)

Staging (Azure Container Apps)

Support for Azure Container Apps with wildcard environment hashes:

from fastapi import FastAPI
from netrun_cors import CORSPreset

app = FastAPI()
app.add_middleware(
    CORSPreset.staging(
        container_apps=["intirkast-frontend", "meridian-frontend"],
        region="eastus2"
    )
)

Configuration:

  • Origins: https://localhost:3000, 5173 + Azure Container Apps wildcards
  • Credentials: Enabled
  • Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH
  • Headers: Authorization, Content-Type, Accept, X-Requested-With, X-Request-ID
  • Max Age: 1800s (30 minutes)

Optional Additional Origins:

app.add_middleware(
    CORSPreset.staging(
        container_apps=["test-app"],
        additional_origins=["https://staging.example.com"]
    )
)

OAuth (Social Platform Integration)

Whitelist OAuth callback domains for social login flows:

from fastapi import FastAPI
from netrun_cors import CORSPreset

app = FastAPI()
app.add_middleware(
    CORSPreset.oauth(
        app_origins=["https://app.intirkast.com"],
        platforms=["google", "twitter", "linkedin", "facebook"]
    )
)

Configuration:

  • Origins: App origins + OAuth platform domains
  • Credentials: Enabled
  • Methods: All (*)
  • Headers: All (*)
  • Expose Headers: All (*)
  • Max Age: 3600s (1 hour)

Supported Platforms:

Platform Domain
google https://accounts.google.com
twitter https://twitter.com
linkedin https://www.linkedin.com
facebook https://www.facebook.com
tiktok https://www.tiktok.com
instagram https://www.instagram.com
pinterest https://www.pinterest.com
threads https://www.threads.net

Advanced Usage

Custom Configuration

If presets don't match your requirements, use CORSPreset.custom():

from netrun_cors import CORSPreset

app.add_middleware(
    CORSPreset.custom(
        allow_origins=["https://app.example.com"],
        allow_credentials=True,
        allow_methods=["GET", "POST"],
        allow_headers=["Authorization", "Content-Type"],
        expose_headers=["X-Request-ID"],
        max_age=1200
    )
)

OWASP Compliance Validation:

The custom preset validates against OWASP security guidelines:

# ❌ This will raise ValueError
app.add_middleware(
    CORSPreset.custom(
        allow_origins=["*"],  # Wildcard
        allow_credentials=True  # Credentials enabled
    )
)
# ValueError: OWASP Violation: Cannot use wildcard origins with credentials

Environment Variable Configuration

Use CORSConfig for environment-based configuration:

from netrun_cors import CORSConfig

config = CORSConfig()
# Reads from environment variables:
# CORS_ORIGINS=https://app.example.com,https://www.example.com
# CORS_ALLOW_CREDENTIALS=true
# CORS_MAX_AGE=3600

app.add_middleware(
    CORSPreset.production(origins=config.CORS_ORIGINS)
)

.env file example:

CORS_ORIGINS=https://app.example.com,https://www.example.com
CORS_ALLOW_CREDENTIALS=true
CORS_ALLOW_METHODS=GET,POST,PUT,DELETE
CORS_ALLOW_HEADERS=Authorization,Content-Type
CORS_EXPOSE_HEADERS=X-Request-ID,X-Process-Time
CORS_MAX_AGE=3600

Migration Guide

Before: Manual CORS Configuration

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:3000",
        "http://localhost:5173",
        "https://app.intirkast.com",
        "https://intirkast-frontend.orangesmoke-f0fb748a.eastus2.azurecontainerapps.io",
        "https://accounts.google.com",  # Google OAuth
        "https://twitter.com",  # Twitter OAuth
        "https://www.linkedin.com",  # LinkedIn OAuth
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["X-Request-ID", "X-Process-Time"],
    max_age=3600,
)

LOC: 18 lines


After: netrun-cors

from fastapi import FastAPI
from netrun_cors import CORSPreset

app = FastAPI()
app.add_middleware(
    CORSPreset.oauth(
        app_origins=["https://app.intirkast.com"],
        platforms=["google", "twitter", "linkedin"]
    )
)

LOC: 2 lines (89% reduction)


Security Best Practices

1. Production Origin Whitelisting

Always use explicit origin lists in production:

# ✅ Secure (explicit origins)
app.add_middleware(
    CORSPreset.production(origins=["https://app.example.com"])
)

# ❌ Insecure (wildcard in production)
app.add_middleware(
    CORSPreset.custom(allow_origins=["*"], allow_credentials=False)
)

2. HTTPS Only in Production

Use HTTPS origins for production deployments:

# ✅ Secure (HTTPS)
origins = [
    "https://app.example.com",
    "https://www.example.com"
]

# ❌ Insecure (HTTP in production)
origins = [
    "http://app.example.com",  # Vulnerable to MITM attacks
]

3. Minimize Exposed Headers

Only expose headers your frontend needs:

# ✅ Minimal (production)
expose_headers = ["X-Request-ID"]

# ⚠️ Permissive (development only)
expose_headers = ["*"]

4. Preflight Caching

Use appropriate max_age for preflight caching:

# Production: 1 hour (reduces preflight overhead)
app.add_middleware(CORSPreset.production(origins=[...]))  # max_age=3600

# Development: 10 minutes (faster iteration)
app.add_middleware(CORSPreset.development())  # max_age=600

Testing

Run the test suite with pytest:

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=netrun_cors --cov-report=term-missing

# Run tests with verbose output
pytest -v

API Reference

CORSPreset

Factory class for standardized CORS middleware configurations.

Methods

development()

Permissive CORS for local development (localhost origins).

Returns: CORSMiddleware

Example:

app.add_middleware(CORSPreset.development())

staging(container_apps, region, additional_origins)

Azure Container Apps staging environment with wildcard support.

Parameters:

  • container_apps (List[str]): Azure Container App names
  • region (str): Azure region (default: "eastus2")
  • additional_origins (Optional[List[str]]): Additional origins to whitelist

Returns: CORSMiddleware

Example:

app.add_middleware(
    CORSPreset.staging(
        container_apps=["test-app"],
        region="westus2"
    )
)

production(origins)

Production deployment with explicit origin whitelisting.

Parameters:

  • origins (List[str]): List of allowed production origins

Returns: CORSMiddleware

Example:

app.add_middleware(
    CORSPreset.production(origins=["https://app.example.com"])
)

oauth(app_origins, platforms)

OAuth-enabled applications with social platform callback domains.

Parameters:

  • app_origins (List[str]): Application origins
  • platforms (List[str]): OAuth platform identifiers

Returns: CORSMiddleware

Raises:

  • ValueError: If invalid platform identifier provided

Example:

app.add_middleware(
    CORSPreset.oauth(
        app_origins=["https://app.example.com"],
        platforms=["google", "twitter"]
    )
)

custom(**kwargs)

Custom CORS configuration with full control.

Parameters:

  • allow_origins (List[str]): List of allowed origins
  • allow_credentials (bool): Allow credentials (default: True)
  • allow_methods (Optional[List[str]]): Allowed HTTP methods
  • allow_headers (Optional[List[str]]): Allowed headers
  • expose_headers (Optional[List[str]]): Exposed headers
  • max_age (int): Preflight cache duration in seconds

Returns: CORSMiddleware

Raises:

  • ValueError: If wildcard origins combined with credentials

Example:

app.add_middleware(
    CORSPreset.custom(
        allow_origins=["https://app.example.com"],
        allow_methods=["GET", "POST"],
        max_age=1200
    )
)

CORSConfig

Pydantic settings for type-safe CORS configuration with environment variable support.

Attributes:

  • CORS_ORIGINS (List[str]): Allowed origins (default: localhost)
  • CORS_ALLOW_CREDENTIALS (bool): Allow credentials (default: True)
  • CORS_ALLOW_METHODS (List[str]): Allowed methods (default: ["*"])
  • CORS_ALLOW_HEADERS (List[str]): Allowed headers (default: ["*"])
  • CORS_EXPOSE_HEADERS (List[str]): Exposed headers (default: ["X-Request-ID", "X-Process-Time"])
  • CORS_MAX_AGE (int): Preflight cache duration (default: 3600)

Example:

from netrun_cors import CORSConfig

config = CORSConfig()
print(config.CORS_ORIGINS)  # ['http://localhost:3000', 'http://localhost:5173']

Performance Considerations

Preflight Caching

CORS preflight requests (OPTIONS) can add latency. Use max_age to cache preflight responses:

Environment max_age Rationale
Development 600s (10 min) Fast iteration, frequent changes
Staging 1800s (30 min) Balance between testing and performance
Production 3600s (1 hour) Maximum performance, stable configuration

Origin Matching Performance

Explicit origin lists have O(n) lookup time. For large origin lists (100+), consider:

  1. Using a reverse proxy (Nginx, Cloudflare) for CORS
  2. Implementing origin caching in your application
  3. Grouping origins by environment (dev, staging, prod)

Troubleshooting

Common Issues

1. CORS Error: "No 'Access-Control-Allow-Origin' header"

Cause: Origin not whitelisted in CORS configuration

Solution: Add origin to allowed list:

app.add_middleware(
    CORSPreset.production(
        origins=[
            "https://app.example.com",
            "https://new-origin.example.com"  # Add missing origin
        ]
    )
)

2. CORS Error: "Wildcard with credentials"

Cause: Attempting to use allow_origins=["*"] with allow_credentials=True

Solution: Use explicit origins or disable credentials:

# Option 1: Explicit origins (recommended)
app.add_middleware(
    CORSPreset.production(origins=["https://app.example.com"])
)

# Option 2: Disable credentials
app.add_middleware(
    CORSPreset.custom(allow_origins=["*"], allow_credentials=False)
)

3. OAuth Callback Failure

Cause: OAuth platform domain not whitelisted

Solution: Use oauth preset with appropriate platforms:

app.add_middleware(
    CORSPreset.oauth(
        app_origins=["https://app.example.com"],
        platforms=["google", "twitter", "linkedin"]
    )
)

4. Azure Container Apps Staging Issues

Cause: Dynamic environment hash not matching

Solution: Use staging preset with wildcard support:

app.add_middleware(
    CORSPreset.staging(
        container_apps=["intirkast-frontend"],
        region="eastus2"
    )
)

Contributing

Contributions welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/new-preset)
  3. Write tests for new functionality
  4. Ensure tests pass (pytest)
  5. Run linters (black, ruff, mypy)
  6. Submit a pull request

License

MIT License - see LICENSE file for details.


Support

Issues: GitHub Issues Email: support@netrunsystems.com Documentation: GitHub Repository


Changelog

v1.0.0 (2025-11-25)

Initial Release:

  • 4 preset configurations (development, staging, production, oauth)
  • OWASP compliance validation
  • 8 OAuth platform support
  • Azure Container Apps integration
  • Pydantic configuration support
  • Comprehensive test suite (90%+ coverage)

Developed by Netrun Systems

Metadata

Release files for netrun-cors 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for netrun-cors 2.1.0
File Size Uploaded Provenance Actions
netrun_cors-2.1.0.tar.gz 15.6 kB Without provenance Details for netrun_cors-2.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for netrun-cors 2.1.0
File Interpreter ABI Platform Actions
netrun_cors-2.1.0-py3-none-any.whl Python 3 none any Details for netrun_cors-2.1.0-py3-none-any.whl

Total release size: 27.6 kB

Release files / netrun_cors-2.1.0.tar.gz

Download URL netrun_cors-2.1.0.tar.gz
Size 15.6 kB
Tags Source
SHA-256 checksum
How to use checksums
09270bda17b04fc10aab174597215159412dd6055560bc8c8623b0d7528b7f35
BLAKE2b-256 checksum
How to use checksums
dca17bc1facadd96de8ffe76914b069b62c14aa30f07b6540d94126dc6548790
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Release files / netrun_cors-2.1.0-py3-none-any.whl

Download URL netrun_cors-2.1.0-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cdb6661109b7fb5d5e2900c56239152e4b3f3b7cea741cb3cbafb7d30e93a579
BLAKE2b-256 checksum
How to use checksums
13abbca91e1f2c9a230a0559700c8b7582e64c4988e458baa307401de446d42c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Security for netrun-cors 2.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page