8

I have an app written with Flask and try to use Flask-Dance (Flask-Dance Docs - Google Example) to enable Google OAuth. I got the following setup:

from flask import redirect, url_for, jsonify, Blueprint
from flask_dance.contrib.google import make_google_blueprint, google

from server.app import app

# Internal auth blueprint
auth = Blueprint('auth', __name__, url_prefix='/auth')

# Google auth blueprint
google_login = make_google_blueprint(
    client_id=app.config['GOOGLE_CLIENT_ID'],
    client_secret=app.config['GOOGLE_CLIENT_SECRET'],
    scope=['profile', 'email']
)


def auth_google_view():
    """
    Authenticate user with google
    """

    # Not authorized
    print(google.authorized)
    if not google.authorized:
        return redirect(url_for('google.login'))

    # Authorized - check data
    user_info = google.get('/oauth2/v2/userinfo')
    if user_info.ok:
        return jsonify({'status': 'ok', 'email': user_info.json() .['email']}), 200
    return jsonify({'status': 'failed'})


# Add urls
auth.add_url_rule('/google', view_func=auth_google_view)

And then in the app/__init__.py:

from server.app.auth import auth, google_login

app.register_blueprint(auth)
app.register_blueprint(google_login, url_prefix='/google_login')

By clicking on button in the app I go to /auth/google and there (after redirects) I can see a google accounts list to choose from. When I select an account in the Network dev tools I see the following routing (url parameters missing):

  1. https://accounts.google.com/_/signin/oauth?authuser=
  2. http://127.0.0.1:8001/google_login/google/authorized?state=
  3. http://127.0.0.1:8001/google_login/google

And then:

  1. https://accounts.google.com/o/oauth2/auth?response_type= ...

all starts from the beginning and I see a "choose account" screen.

In the Google API account I have a redirect url:

http://127.0.0.1:8001/google_login/google/authorized

In the development environment I set OAUTHLIB_INSECURE_TRANSPORT=1 and OAUTHLIB_RELAX_TOKEN_SCOPE=1

It seems like the third URL in routing should be /auth/google and try to resolve google.authorized once again but it does not and I see result of print(google.authorized) # False only once when click on a google button inside the app.

singingwolfboy
  • 5,336
  • 3
  • 27
  • 32
Max
  • 404
  • 2
  • 17
  • 39

1 Answers1

6

The blueprint generated by make_google_blueprint defaults to redirecting towards / when the authentication cycle has ended; you can configure this using the parameters redirect_url or redirect_to. In your case:

google_login = make_google_blueprint(
  client_id=app.config['GOOGLE_CLIENT_ID'],
  client_secret=app.config['GOOGLE_CLIENT_SECRET'],
  scope=['profile', 'email'],
  redirect_to='auth.auth_google_view'
)

EDIT: Also make sure your app has a good secret_key set.

Luis Orduz
  • 2,887
  • 1
  • 13
  • 19
  • Thank you for the answer! I tried to play with `redirect_url` and `redirect_to`. Now I wrote `redirect_to='auth.google'` and get a werkzeug error, so it has been handled. Then I correct it to `auth.auth_google_view` and still has the same issue with routing: /auth/google -> /google_login/google -> (choose account) -> /google_login/google -> (choose account) ... And still see `print(google.authorized)` only once on button click. How it's possible? – Max Apr 16 '18 at 08:17
  • If I set `redirect_url='/auth/google'` after choosing an account it goes /google_login/google/authorized -> /google_login/google and then obviously to (choose account) once again. As I cant find any issues on that I think it should work easily. Why it skip `/auth/google`? – Max Apr 16 '18 at 12:00
  • You're correct on `auth_google_view`, fixed. What happens if you create the view using the decorator instead of with `add_url_rule`? In theory there should be no change, but I replicated your code exactly as is, only with that change, and it works in my local using `redirect_to`. Make sure your app has a `secret_key` too. Here's a [snippet](https://gitlab.com/snippets/1710375) with my code that works. – Luis Orduz Apr 16 '18 at 13:04
  • Decorator instead of `add_url_rule` changed nothing and I checked once again I had `SECRET_KEY`, `GOOGLE_OAUTH_CLIENT_ID` and `GOOGLE_OAUTH_CLIENT_SECRET` set in `app.config`. I'll try your snippet now as it 100% works and come back. – Max Apr 16 '18 at 13:11
  • There might be something in the code you aren't sharing that's messing up the configuration then; make sure you write all the relevant code in the question. In this case, particularly the code that creates `app` and everything that might be changing it. – Luis Orduz Apr 16 '18 at 13:15
  • Wow! I just found out the problem! I ran you snippet and set `GOOGLE_*` configuration but kept yours `SECRET_KEY` value. And everything works ok. Then I changed it to mine random string and got my strange routing behaviour. Then I changed `SECRET_KEY` back to yours and it works ok. I have no idea why this happens (don't you?) but thank you for your point on `SECRET_KEY` I think it would take me ages to figure it out. – Max Apr 16 '18 at 13:24
  • How were you assigning `SECRET_KEY` before? – Luis Orduz Apr 16 '18 at 13:28
  • In a configuration class `SECRET_KEY = '.......'` and then `app.config.from_object(config_class)`. And I'm sure it worked (not for the google oauth). But now if I changed it in the snippet or in the configuration class in the project to your value it's working, back to mine - nope. – Max Apr 16 '18 at 13:32
  • Odd, maybe some character was causing trouble. Still, don't use mine, use a random string properly generated, like [in this answer](https://stackoverflow.com/a/34903502/4570188). – Luis Orduz Apr 16 '18 at 13:39
  • Sure, I have changed it already. But my former key does not contain any characters besides alphanumeric. Once again, thank you for your time! – Max Apr 16 '18 at 13:42