[Python] How to handle dynamic origin in FastAPI

Discussão em 'Python' iniciado por Stack, Maio 22, 2025.

  1. Stack

    Stack Membro Participativo

    I'm implementing a FastAPI backend where I want to allow CORS requests only from a predefined list of default origins and dynamically loaded origins stored in the database.

    However, when the frontend tries to call a GET API, the browser first sends an OPTIONS preflight request (as expected for CORS). The problem is:

    The OPTIONS request fails due to a CORS error.

    As a result, the actual GET request is never made.

    This issue suggests that the CORS middleware is not properly handling the dynamic origins, especially during the OPTIONS preflight phase.

    from fastapi.security import HTTPBasic, HTTPBasicCredentials
    from starlette.middleware.base import BaseHTTPMiddleware,RequestResponseEndpoint

    origins = [
    "http://localhost:3000",
    "http://localhost:3001",
    "http://localhost:8006",
    ]

    class DynamicCORSMiddleware(BaseHTTPMiddleware):
    def __init__(self, app: ASGIApp):
    super().__init__(app)

    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
    origin = request.headers.get("origin")
    ic(origin)
    ic(request.method)
    # Preflight request
    if request.method == "OPTIONS":
    response = JSONResponse(content={"status": "ok"})
    else:
    response = await call_next(request)

    # If no Origin header, skip CORS (non-browser requests)
    if not origin:
    return response

    if origin in origins:
    ic("Origin in default origins")
    response.headers["Access-Control-Allow-Origin"] = origin
    response.headers["Access-Control-Allow-Credentials"] = "true"
    response.headers["Access-Control-Allow-Headers"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
    response.headers["Vary"] = "Origin"
    return response

    # Extract domain (remove protocol and port)
    ic(origin)
    domain = origin.replace("https://", "").replace("http://", "")
    ic(domain)
    # Check if domain exists in database
    domain_exists = domain_collection.find_one({"$or": [{"domain.main_domain": domain}, {"domain.sub_domain": domain}]})
    if not domain_exists:
    raise HTTPException(
    status_code=403,
    detail=f"Domain {domain} not authorized"
    )
    ic(domain_exists)

    # Process request
    response = await call_next(request)

    response.headers["Access-Control-Allow-Origin"] = origin
    response.headers["Access-Control-Allow-Credentials"] = "true"
    response.headers["Access-Control-Allow-Headers"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
    response.headers["Vary"] = "Origin"
    ic(response)
    return response
    enter code here

    app = FastAPI(
    title="API",
    description="API documentation for backend",
    version="1.0.0",
    docs_url=None, # Disable the default docs URL
    redoc_url=None # Disable the default redoc URL
    )
    app.add_middleware(DynamicCORSMiddleware)

    Continue reading...

Compartilhe esta Página