Search code examples
python-3.xpython-2.7flaskpython-requestsfacebook-access-token

Flask - b' text appears before request.data results


So I for a while I was running my application on Python's Localhost for debugging reasons, but now I desperately want to make my Flask application run on my Apache Localhost. I have configured Ubuntu on Vagrant to run the application on Apache and the only thing that does not work right now is the Facebook Sign-In. While my Google Sign-in method works fine on both Python's Localhost and on Apache, my Facebook Sign-in method only works on Python's Localhost and NOT on Apache's Localhost for some reason.

Specifically, in my fbconnect() method that preforms the fb sign-in functionality, when the code reaches my 4th print( print("4. FB http request results: %s" % result) ) of the given code block (scroll down for the block of code), the message given off by the 4th print is this error:

4. FB http request results: b'{"error":{"message":"Invalid OAuth access token.","type":"OAuthException","code":190,"fbtrace_id":"AjWGMxq54MULV0sCpjpW2DT"}}'

I don't know what the b' is doing there (it appears right at the start of the error message) and how to remove it, but it also appears in the 1st print( _print("1. Access token: %s " % access_token)_ ) :

1. Access token: b'EAAE7dgXeMUup...'

and it does NOT appear in the 2nd or the 3rd print:

2. App ID: 3425...
3. App secret: 75a2...

I think that the problem is caused by those b' since they do not appear in my prints when I run the app on my Python Localhost and they also do not appear in the 2nd or 3rd prints on Apache, but I'm not sure as they might be appearing because the print output is somehow changed when I write out the messages in a 'print.log' file, since Apache doesn't actually print out messages to the terminal like Python's Localhost does. Here's my fbconnect() method:

def fbconnect():

    ''' Validate state token, by confirming that the token that the client sends
    to the server matches the token that the server sent to the client. This
    round-trip verification helps ensure that the user is making the request
    not a malicious script. Using the request.args.get() method, we examine
    the state token passed in by the ajax request and compare with the state
    of the login_session. If these 2 do NOT match, we create a response of an
    invalid state token and return this message to the client. '''

    if request.args.get('state') != login_session['state']:
        response = make_response(json.dumps('Invalid state parameter.'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response
    access_token = request.data
    print("1. Access token: %s " % access_token)

    # Get Facebook app ID.
    app_id = json.loads(open('/vagrant/Inhinito/fb_client_secrets.json', 'r').read())['web']['app_id']
    print("2. App ID: %s " % app_id)

    # Get Facebook app secret.
    app_secret = json.loads(open('/vagrant/Inhinito/fb_client_secrets.json', 'r').read())['web']['app_secret']
    print("3. App secret: %s " % app_secret)

    # Make http request to the Facebook API.
    url = "https://graph.facebook.com/oauth/access_token?client_id=%s" % (app_id)
    url += "&client_secret=%s&grant_type=fb_exchange_token" % (app_secret)
    url += "&fb_exchange_token=%s" % (access_token)
    http = httplib2.Http()
    result = http.request(url, 'GET')[1]
    print("4. FB http request results: %s" % result)

    ....

Here's the correct output that I get from Python's Localhost:

1. Access token: EAgE7...
4. FB http request results: {"access_token":"EAgE7...","token_type":"bearer","expires_in":5183999}

Solution

  • As Doobeh mentioned in the comments the solution is to decode the data sent by the client-side to UTF-8. This is a Python2 vs Python3 issue explained in detail here.

    The b' ' apparently is used to indicate the string is binary, as opposed to Unicode. The solution is to use access_token = request.data.decode('UTF-8') Instead of access_token = request.data and http.request(url, 'GET')[1].decode('UTF-8') instead of http.request(url, 'GET')[1].