I use the following route to redirect an authenticated OAuth user to their account page:
@app.route('/google/callback')
def authorized():
resp = google.authorized_response()
if resp is None:
return 'Access denied: reason={0} error={1}'.format(
request.args['error_reason'],
request.args['error_description']
)
session['google_token'] = (resp['access_token'], '')
return redirect(url_for('account',_external=True, _scheme='https'))
However the redirect URL is to http://[domain].herokuapp.com/google/callback. Navigating between pages within my application keeps me in an https environment; it’s just when I leave the application to authenticate and get redirected back that it switches to http. Why is that, and how can I make it redirect back to https?
>Solution :
Your application is behind a reverse proxy (in this case, Heroku’s router) that is serving the app through HTTPS, but your Flask application is not aware of it. You need to make sure that Flask is aware of the reverse proxy and the correct scheme. One way to do this is using the ProxyFix middleware from Werkzeug. First, install werkzeug:
pip install Werkzeug
Then add this code to your application:
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
# Setting x_proto to 1 indicates that ProxyFix will look at the X-Forwarded-Proto header
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1)
Now, Flask should use the correct scheme when redirecting users.
To ensure that this configuration works also in non-proxy/non-HTTPS environments (e.g., local development), you can conditionally activate the ProxyFix middleware:
import os
if os.environ.get('FLASK_ENV') == 'production':
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1)
This will only apply the middleware when your FLASK_ENV environment variable is set to production.
Additionally, if you want to enforce HTTPS for all requests, use the Flask-Talisman library:
pip install flask-talisman
Then add it to your application:
from flask_talisman import Talisman
Talisman(app)
This library forces all requests to be made over HTTPS. Keep in mind this will affect all routes in your application.