Search code examples
httpsjinja2fastapiuvicorn

FastAPI links created by url_for in Jinja2 template use HTTP instead of HTTPS


I migrated an application in Flask served by waitress to FastAPI served by uvicorn, but I can't force the links (generated by url_for inside the index.html template) to use HTTPS instead of HTTP.

With waitress I used:

from waitress import serve
import flask_app

PORT=5000
HOST_IP_ADDRESS='0.0.0.0'

serve(flask_app.app, host=HOST_IP_ADDRESS, port=PORT, url_scheme="https")

with uvicorn I tried to use proxy_headers, but that didn't work. I used a workaround in the index.html

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

which correctly loaded the style.css from static files, but the links to another endpoint still use HTTP.

Is there an easy way to force all links created by url_for to use HTTPS?


Solution

  • I have also run into this issue before. One possible solution is to create a custom url_for function which changes the protocol, then add it to the Jinja environment. One possible implementation may look something like this:

    template = Jinja2Templates("/path/to/templates")
    
    def https_url_for(request: Request, name: str, **path_params: Any) -> str:
    
        http_url = request.url_for(name, **path_params)
    
        # Replace 'http' with 'https'
        return http_url.replace("http", "https", 1)
    
    template.env.globals["https_url_for"] = https_url_for
    

    You will have to pass the request to the function so it knows how to generate the url_for, but the request should be passed in to your Jinja2 template either way.

    You can then use it in your Jinja2 template like this:

    https_url_for(request, "/https/path", search="hi")
    

    The resulting url should look like https://<domain>/https/path?search=hi.