Proxies and HTTPS

Running a secure HTTPS website is important, but encrypting and decrypting HTTPS traffic is computationally expensive. Many people running large-scale websites (including Heroku) use a TLS termination proxy to reduce load on the HTTP server. This works great, but means that the webserver running your Flask application is actually speaking HTTP, not HTTPS.

As a result, Flask-Dance can get confused, and generate callback URLs that have an http:// scheme, instead of an https:// scheme. This is bad, because OAuth requires that all connections use HTTPS for security purposes, and OAuth providers will reject requests that suggest a callback URL with a http:// scheme.

When you proxy the request from a TLS termination proxy, probably your load balancer, you need to ensure a few headers are set/proxied correctly for Flask to do the right thing out of the box:

  • Host: preserve the Host header of the original request
  • X-Real-IP: preserve the source IP of the original request
  • X-Forwarded-For: a list of IP addresses of the source IP and any HTTP proxies we’ve been through
  • X-Forwarded-Proto: the protocol, http or https, that the request came in with

In 99.9% of the cases the TLS termination proxy will be configured to do the right thing by default and any well-behaved Flask application will work out of the box. However, if you’re accessing the WSGI environment directly, you will run into trouble. Don’t do this and instead use the functions provided by Werkzeug’s wsgi module or Flask’s request to access things like a Host header.

If your Flask app is behind a TLS termination proxy, and you need to make sure that Flask is aware of that, check Flask’s documentation for how to deploy a proxy setup.

Please read it and follow its instructions. This is not unique to Flask-Dance and there’s nothing to configure on Flask-Dance’s side to solve this. It’s also worth noting you might wish to set Flask’s PREFERRED_URL_SCHEME.