LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-14-2017, 06:53 PM   #1
manolakis
Member
 
Registered: Nov 2006
Distribution: xubuntu
Posts: 464

Rep: Reputation: 37
Flask Google sign in problem


Hello,

I am writing a Web App in Flask, and I have a template index.html which checks if a user is not signed in. If not a sign in button is displayed.

Code:
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
    <head>
        <title>Item catalog Application</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
        </script>
        <script src="//apis.google.com/js/platform.js?onload=start">            
        </script>
    </head>
    <body>
        <div>TODO write content</div>
        {% if not username in log_session %}
        <div id="signInButton">
          <span class="g-signin"
            data-scope="openid email"
            data-clientid="609704772765-ip5d9e502amk9r0u8rh9t3q18qdmoos8.apps.googleusercontent.com"
            data-redirecturi="postmessage"
            data-accesstype="offline"
            data-cookiepolicy="single_host_origin"
            data-callback="signInCallback"
            data-approvalprompt="force">
          </span>
        </div>
        {% else %}
        <a href="/gdisconnect">Logout</a>
        {% endif %}
    </body>
</html>
My application.py is the following:
Code:
from flask import Flask, render_template, request, redirect, jsonify, url_for, flash
from flask import session as login_session
import random
import string

# IMPORTS FOR THIS STEP
from oauth2client.client import flow_from_clientsecrets
from oauth2client.client import FlowExchangeError
import httplib2
import json
from flask import make_response
import requests

app = Flask(__name__)

CLIENT_ID = json.loads(
    open('client_secrets.json', 'r').read())['web']['client_id']
APPLICATION_NAME = "Item Catalog Application"

data = {"Snowboarding":[{"title":"Snowboard", "description":"A snowboard for skying"}, {"title":"Jacket", "description":"Waterproof jacket"}],
        "Basketball":[{"title":"Basket ball", "description":"A basket ball"}, {"title":"shoes", "desctiption":"Basketball shoes"}],
        "Soccer":[{"title":"Soccer ball", "description":"A soccer ball"}, {"title":"shoes", "desctiption":"Soccer shoes"}],
        }

@app.route('/')
@app.route('/index')
def hello_world():
    return render_template('index.html');

@app.route('/catalog.json')
def getJSON():
    return str(data)

@app.route('/gconnect', methods=['POST'])
def gconnect():

    state = ''.join(random.choice(string.ascii_uppercase + string.digits)
                    for x in range(32))
    login_session['state'] = state

    # Validate state token
    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
    # Obtain authorization code
    code = request.data

    try:
        # Upgrade the authorization code into a credentials object
        oauth_flow = flow_from_clientsecrets('client_secrets.json', scope='')
        oauth_flow.redirect_uri = 'postmessage'
        credentials = oauth_flow.step2_exchange(code)
    except FlowExchangeError:
        response = make_response(
            json.dumps('Failed to upgrade the authorization code.'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response

    # Check that the access token is valid.
    access_token = credentials.access_token
    url = ('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=%s'
           % access_token)
    h = httplib2.Http()
    result = json.loads(h.request(url, 'GET')[1])
    # If there was an error in the access token info, abort.
    if result.get('error') is not None:
        response = make_response(json.dumps(result.get('error')), 500)
        response.headers['Content-Type'] = 'application/json'
        return response

    # Verify that the access token is used for the intended user.
    gplus_id = credentials.id_token['sub']
    if result['user_id'] != gplus_id:
        response = make_response(
            json.dumps("Token's user ID doesn't match given user ID."), 401)
        response.headers['Content-Type'] = 'application/json'
        return response

    # Verify that the access token is valid for this app.
    if result['issued_to'] != CLIENT_ID:
        response = make_response(
            json.dumps("Token's client ID does not match app's."), 401)
        print("Token's client ID does not match app's.")
        response.headers['Content-Type'] = 'application/json'
        return response

    stored_credentials = login_session.get('credentials')
    stored_gplus_id = login_session.get('gplus_id')
    if stored_credentials is not None and gplus_id == stored_gplus_id:
        response = make_response(json.dumps('Current user is already connected.'),
                                 200)
        response.headers['Content-Type'] = 'application/json'
        return response

    # Store the access token in the session for later use.
    login_session['credentials'] = credentials
    login_session['gplus_id'] = gplus_id

    # Get user info
    userinfo_url = "https://www.googleapis.com/oauth2/v1/userinfo"
    params = {'access_token': credentials.access_token, 'alt': 'json'}
    answer = requests.get(userinfo_url, params=params)

    data = answer.json()

    login_session['username'] = data['name']
    login_session['picture'] = data['picture']
    login_session['email'] = data['email']

    return redirect(url_for('index.html'))

@app.route('/gdisconnect')
def gdisconnect():
    access_token = login_session['access_token']
    print
    'In gdisconnect access token is %s', access_token
    print
    'User name is: '
    print
    login_session['username']
    if access_token is None:
        print
        'Access Token is None'
        response = make_response(json.dumps('Current user not connected.'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response
    url = 'https://accounts.google.com/o/oauth2/revoke?token=%s' % login_session['access_token']
    h = httplib2.Http()
    result = h.request(url, 'GET')[0]
    print
    'result is '
    print
    result
    if result['status'] == '200':
        del login_session['access_token']
        del login_session['gplus_id']
        del login_session['username']
        del login_session['email']
        del login_session['picture']
        response = make_response(json.dumps('Successfully disconnected.'), 200)
        response.headers['Content-Type'] = 'application/json'
        return response
    else:

        response = make_response(json.dumps('Failed to revoke token for given user.', 400))
        response.headers['Content-Type'] = 'application/json'
        return response

if __name__ == '__main__':
    app.run()
The problem with the application is that although that successfully signs in with Google it does not sign in with my website, and after redirecting to index.html again it does not show the user as registered.
Could anybody with experience in Flask help me?

Thank you.
 
Old 07-15-2017, 03:28 PM   #2
audriusk
Member
 
Registered: Mar 2011
Location: Klaipėda, Lithuania
Distribution: Slackware
Posts: 360

Rep: Reputation: 199Reputation: 199
Can't help you with your problem as I have virtually no experience with OAuth, just wanted to note some things in your code.

Instead of writing this:
Code:
response = make_response(json.dumps('Invalid state parameter.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
it's easier to write this (it will handle Content-Type header for you):
Code:
# from flask import jsonify
return jsonify('Invalid state parameter.'), 401
Same here:
Code:
@app.route('/catalog.json')
def getJSON():
    # Use jsonify() instead of str().
    return str(data)
The following snippet doesn't make sense to me:
Code:
state = ''.join(random.choice(string.ascii_uppercase + string.digits)
                for x in range(32))
login_session['state'] = state

# Validate state token
if request.args.get('state') != login_session['state']:
    # Return error response...
You generate random string and then compare it with another string that you get as an argument for HTTP request. This if-statement will almost always be true.

It's also not clear to me why you're using two separate HTTP client libraries, httplib2 and requests, in the same project. Just stick to one, I recommend the latter, it's easier to use and more popular.
 
1 members found this post helpful.
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
LXer: Google's Chrome OS Team Is Experimenting with Refreshed Sign-In/Lock Screens LXer Syndicated Linux News 0 06-26-2017 01:06 AM
LXer: Install Picasa 3.9 In Linux And Fix Google Sign In Issue Wine LXer Syndicated Linux News 0 01-04-2012 09:40 PM
LXer: Attackers hit Google single sign-on password system LXer Syndicated Linux News 0 04-22-2010 05:41 AM
LXer: Google SoC 2007 - we're in, sign up quickly! LXer Syndicated Linux News 0 03-16-2007 08:31 AM
LXer: Realnetworks, Google, Mozilla Sign Distribution Deals LXer Syndicated Linux News 0 08-04-2006 11:54 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 12:46 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration