1
votes

I'm trying to access user's new access token via a POST call from chrome extension to my website that the user gave permission to. Thus, all of google doc that's dependant on redirects & user being on the session wouldn't work for me.

I can't seem to figure out how to integrate google's refresh access token with User's credentials (client_id, client_secret, refresh_token, grant_type) stored in db.

@blueprint.route("Calendar", methods=['POST'])
def Calendar():

    flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES) #believe should be added or else flow would be undefined (even though not present in the code snippet)

    authorization_url, state = flow.authorization_url(
      # Enable offline access so that you can refresh an access token without
      # re-prompting the user for permission. Recommended for web server apps.
      access_type='offline',
      # Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes='true')

I tried adding:

# Use the authorization server's response to fetch the OAuth 2.0 tokens.
authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)
credentials = flow.credentials
flask.session['credentials'] = credentials

user = User.query.filter_by(email=email).first()  
with open('client_secret.json') as d:
    d = json.load(d)
service = build('calendar', 'v3', credentials=credentials)

& got:

oauthlib.oauth2.rfc6749.errors.MismatchingStateError: (mismatching_state) CSRF Warning! State not equal in request and response.
1

1 Answers

1
votes

Unfortunately not all Google samples are created alike and the Google calendar sample is lacking in an example of what you are trying to do.

Try checking the Google Analytics quick start Python this sample has a very nice example of how to set up storage of the refresh token and how to use it when needed.

 # Prepare credentials, and authorize HTTP object with them.
  # If the credentials don't exist or are invalid run through the native client
  # flow. The Storage object will ensure that if successful the good
  # credentials will get written back to a file.
  storage = file.Storage('calendar.dat')
  credentials = storage.get()
  if credentials is None or credentials.invalid:
    credentials = tools.run_flow(flow, storage, flags)
  http = credentials.authorize(http=httplib2.Http())

The sample for Google drive sample also has something like it.

# The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

I am not telling you to switch APIs here i am simply suggesting that you check how the authorization code works in the other two tutorials. You will need to pass your existing scopes for calendar and NOT the scopes for drive or analytics. The methods you are using to access your events will not change you are only changing how the authorization functions.

I am not a python dev so cant really help you alter it more then that.