Ad

How To Get New Token.json For Google Apps Script API (or Google Cloud Platform) Through Flask App

I have a flask app that I want to authenticate to use a google apps script API. If I create a token.json file with this quickstart link it takes me to the authentication page and then creates a token.json file for me even if I've deleted it or its expired. This is what I want to do in my flask app (because tokens expire so I want to be able to refresh them). The code I'm using is

# Setup the Apps Script API scopes
SCOPES = ['https://www.googleapis.com/auth/script.projects',
'https://www.googleapis.com/auth/script.external_request',
'https://www.googleapis.com/auth/spreadsheets']

def getCredentialsAppScript():
    store = oauth_file.Storage('token.json')
    creds = store.get()
    if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
        creds = tools.run_flow(flow, store)
    return creds

then in getListItems (code snippet)

@app.route("/getListItems", methods=["POST", "GET"])
def getListItems():
    
    """Runs the sample.
    """
    SCRIPT_ID = 'xxxxxxxxxxxxxx'

    creds = getCredentialsAppScript()

    service = build('script', 'v1', credentials=creds)

    # Create an execution request object.
    request = {"function": "getTokensForUser"}

the error simply says UserWarning: Cannot access token.json: No such file or directory what I don't understand is why I can't get a new token.json through the code block in the flask app but when running the quickstart.py it takes me to the google sign-in page if I don't have a token.json.

if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
        creds = tools.run_flow(flow, store)
Ad

Answer

I think that you may lack some information about OAuth2 and its implementation in Google API's.

I would strongly encourage you to read the documentation for Server side OAuth there is even a full example of an authorization, token revoke and API test call in flask.


In specific the problem with your code is that you are copying the structure as the python quickstart but you have to remember that the quickstart is meant to be executed as a command line program, not as a server side as Flask.

So because you are now in a server environment you first need to redirect the user to a google authorization page:

# Copied from https://developers.google.com/identity/protocols/oauth2/web-server#python_5

@app.route('/authorize')
def authorize():
  # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES)

  # The URI created here must exactly match one of the authorized redirect URIs
  # for the OAuth 2.0 client, which you configured in the API Console. If this
  # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
  # error.
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  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')

  # Store the state so the callback can verify the auth server response.
  flask.session['state'] = state

  return flask.redirect(authorization_url)

And later receive the authorization object in the oauth2callback function:

# Copied from https://developers.google.com/identity/protocols/oauth2/web-server#python_5
@app.route('/oauth2callback')
def oauth2callback():
  # Specify the state when creating the flow in the callback so that it can
  # verified in the authorization server response.
  state = flask.session['state']

  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  # 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)

  # Store credentials in the session.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  credentials = flow.credentials
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.redirect(flask.url_for('<Your function calling the API>'))

Ad
source: stackoverflow.com
Ad