litl / rauth

A Python library for OAuth 1.0/a, 2.0, and Ofly.
http://readthedocs.org/docs/rauth/en/latest/
MIT License
1.61k stars 175 forks source link

the JSON object must be str, not 'bytes' #194

Open leonardopessoa opened 7 years ago

leonardopessoa commented 7 years ago

Trying to implement a OAuth2 authentication on Django 1.10 + Python 3, I'm getting this error:

rauth: the JSON object must be str, not 'bytes' It happens on the line calling: session = sso.get_auth_session(data=data, decoder=json.loads).

If i remove the decoder=json.loads, I get the following error:

Decoder failed to handle access_token with data as returned by provider. A different decoder may be needed.

Here is my method:

def login(request):
    """
    Login view
    @author: Leonardo Pessoa
    @since: 11/06/2016
    """
    from rauth import OAuth2Service
    from django.conf import settings
    import son

    # instantiating our login service with environment defined settings
    sso = OAuth2Service(
        name                = settings.LOGIN_SETTINGS['name'],
        client_id           = settings.LOGIN_SETTINGS['client_id'],
        client_secret       = settings.LOGIN_SETTINGS['client_secret'],
        access_token_url    = settings.LOGIN_SETTINGS['access_token_url'],
        authorize_url       = settings.LOGIN_SETTINGS['authorize_url'],
        base_url            = settings.LOGIN_SETTINGS['base_url'],
    )

    # check if we have a login code returned by OAuth
    get_code = request.GET.get('code', '')
    if get_code == '':
        params = {
            'redirect_uri'    : settings.LOGIN_SETTINGS['redirect'],
            'response_type'   : 'code'
        }
        url = sso.get_authorize_url(**params)

        return redirect(url)
    else:
        # we are in!
        data = {'code'          : get_code,
                'grant_type'    : 'authorization_code',
                'redirect_uri'  : settings.LOGIN_SETTINGS['redirect']
                }

        session = sso.get_auth_session(data=data, decoder=json.loads)

        return redirect('/logado/')

The view is accessed the first time to redirect to the authorize URL (no GET['code']). Next, it's accessed again (with the GET['code']) to handle the authorization code and authenticate.

Feel like there should be a mix of both solutions (encoding UTF-8 + json).

leonardopessoa commented 7 years ago

I still think there should be something more straight forward or even a bug fix to this, but here's my own workaround:

def oauth_decode(data):
    import son

    new_data = data.decode("utf-8", "strict")

    return json.loads(new_data)
...
session = sso.get_auth_session(data=data, decoder=oauth_decode)

The problem is that get_auth_session decodes the byte stream from the response to UTF-8 by default. If you specify a new decoder, you override that. So I guess we need both here (UTF-8 + JSON).