omab/django-social-auth — Issue #281: OAuth2 backend uses incoming request's URI scheme for redirect_uri
Author: marmida
Created: 2012-03-06 03:28:41+00:00
State: open

Overview
-----------

OAuth2 is sensitive to guaranteeing encrypted communication of tokens. The OAuth2 backends in `django-social-auth` use the scheme part of the incoming request, e.g. `http://`' or `https://`, as the basis for the 'redirect_uri` parameter sent with the user's redirect to the provider.

This is a problem if SSL is handled separate from the application's server, e.g. by a reverse proxy. It also causes a problem if the app is hosted on a cloud platform service like heroku, in which the routing mesh also segregates SSL. From django's point of view, all incoming requests are via plain HTTP.

To reproduce
--------------

* create a django project that includes django-social-auth and django-meetup-auth.
* serve the app's SSL behind a reverse proxy
* go to `https://yourapp/login/meetup/`
* the browser is redirected to `https://secure.meetup.com/` with the `redirect_uri` query var starting in `http://yourapp/...`. This causes Meetup to respond with a page "Invalid Authorization request; If you were directed here by another application, contact its developer".
* if you change the redirect_uri in your current query string to begin with `https://` instead of `http://`, Meetup stops complaining.
* if you originally navigated to `http://yourapp/login/meetup` instead of via `https://`, you get the same behavior

Analysis
--------

My non-expert analysis of the problem:

* the request gets routed to `social_auth.views.auth_process` via `auth`
* the view calls `backend.auth_url()` to get the full URL to redirect the browser to the OAuth provider
* `BaseOAuth2.auth_url` sets the `redirect_uri` query string component to `self.redirect_uri`
* `BaseOAuth.__init__` builds `self.redirect_uri` via `self.request.build_absolute_uri(self.redirect)`
* `django.http.HttpRequest.build_absolute_uri` uses `is_secure`
* `django.http.HttpRequest.is_secure` looks at `HTTPS` in the environment to give a yea/nay

This implies that the issue should strike for any OAuth2 exchange behind a reverse proxy, not just for Meetup.

Workaround
-----------------

Here's a cheesy monkey patch to dodge this problem:
https://gist.github.com/1983212

I put this into my app's models.py, and the behavior went away.

What's the best way to fix this? Maybe provide settings to override the auto-calculation of `redirect_uri` from routes? Or find a way to guarantee 'HTTPS' is on in the environment?