Search code examples
oauthaccess-tokendialogflow-esactions-on-googlegoogle-account

Account links successfully but access token shows invalid - Google OAuth


I've been trying to implement Google OAuth service with the implicit flow for my Dialogflow account linking (Using this documentation)

I've developed the code according to that document. It works fine when a user links his account and shows "you've successfully, linked your account with chatbot".

But when I try to use the access token that I've generated in Step 3 of that document, it says that the access token is not valid. Looks like it doesn't register with the Google service!

Here is my code using which I've implemented it

import os
import flask
from flask import request, redirect
import string
import random
from random import choice, randint
import google_auth_oauthlib.flow
from AES import AESCipher
import json

CLIENT_SECRETS_FILE = "client_secret.json"

SCOPES = ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email']
app = flask.Flask(__name__)
app.secret_key = 'SECRET_KEY'

#
# Actions on google call this function with client_id, redirect_uri, state, and response_type
#
@app.route('/auth')
def authorize():
    flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
        CLIENT_SECRETS_FILE, scopes=SCOPES)

    flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

    print ("%%%%STATE", request.args["state"])
    authorization_url, state = flow.authorization_url(
        access_type='offline',
        include_granted_scopes='true')

    flask.session['state'] = request.args["state"]
    print ("IN AUTH STATE ", state)

    return flask.redirect(authorization_url)


def get_user_id():
    min_char = 8
    max_char = 12
    allchar = string.ascii_letters + string.punctuation + string.digits
    password = "".join(choice(allchar) for x in range(randint(min_char, max_char)))
    return password


@app.route('/oauth2callback')
def oauth2callback():
    print ("### IN CALLBACK ###", request)
    state = flask.session['state']

    user_id = get_user_id()
    client_id = ''.join(random.sample("Google", len("Google")))
    key = ''.join(random.sample("JayPatel", len("JayPatel")))
    bytes_obj = {
        'user_id': user_id,
        'client_id': client_id
    }
    access_token = AESCipher("Jay").encrypt(json.dumps(bytes_obj))
    access_token = access_token.replace('+', 'p')
    access_token = access_token.replace('&', '1')

    # My generated access_token looks like 
    # 6u2PeFcUtNmAblw5N3YAKSn7EC46xQVmgv3Rc8XK9sTW4xcgAxw1doRsvmgE/CC2qGUJ1x7XpNpdYvGes6qJHIEQSwvgEJt8hnYEUbm0qEA=
    print ("###### Access Token ", access_token)
    print ("###### State ", state)

    url = "https://oauth-redirect.googleusercontent.com/r/test-happierbot-4c514#access_token=" + access_token + "&token_type=bearer&state=" + state

    return redirect(url)


if __name__ == '__main__':
    os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

    app.run('localhost', 8080, debug=True)

When I try to get the information using access_token by https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=my_generated_token API, it gives

{
    "error": "invalid_token",
    "error_description": "Invalid Value"
}

Is there any other process to activate the access_token or am I missing any step?


Solution

  • If I'm following the code correctly, you're generating your own access token to return to the user, and then using google's "tokeninfo" end point to see if the token is valid?

    Google has no concept of what your token is or means, so it returns that it is invalid. The Assistant uses your service to get a token, and returns it when it sends a message from the user. Otherwise, it just treats it as a bearer token.

    Your service is expected to determine its validity based on whatever means you want (look it up in a table, reverse the process to decrypt and verify it, check for a valid signature, etc). Since Google doesn't know anything about the token, it can't determine if it is actually valid.

    The tokeninfo service returns information about tokens that Google has generated.

    Google does not let you use their token endpoint for OAuth Account Linking. Instead, you can use the Google Sign In for Assistant and this will give you an id token. You can use this along with regular Google Sign In through a website to get an access token and refresh token that you can use to gain access to a user's Google resources with their permission. (See this Stack Overflow answer for more details.)