Question

I have an appengine app that needs to access a single, hard-coded spreadsheet on Google Drive.

Up until now I have been achieving this as follows:

SpreadsheetService service = new SpreadsheetService("myapp");
service.setUserCredentials("myusername@gmail.com", "myhardcodedpassword");

When I tried this today with a new user, I got InvalidCredentialsException even though the username and password were definitely correct. I got an email in my inbox saying suspicions sign-ins had been prevented, and there seems to be no way to enable them again.

I am also aware that hardcoding passwords in source is bad practice.

However, I have read very widely online for how to enable OAuth/OAuth2 for this, and have ended up wasting hours and hours piecing fragments of information from blogs, stackoverflow answers etc, to no avail.

Ideally the solution would involve an initial process to generate a long-lived access token, which could then be hard-coded in to the app.

I want a definitive list of steps for how to achieve this?

Was it helpful?

Solution

EDIT: As Google have redesigned the API Console, the details of the steps below have changed - see comments

OK here goes, step by step

  1. Go to Google Cloud Console and register your project (aka application)
  2. You need to note the Client ID, and Client Secret
  3. Go to the OAuth Playground, click the gear icon and choose and enter your own credentials
  4. You will be reminded that you need to go back to the Cloud COnsole and add the Oauth Playground as a valid callback url. So do that.
  5. Do Step 1, choosing the spreadsheet scope and click authorize
  6. Choose your Google account if prompted and grant auth when prompted
  7. Do Step 2, Click 'Exchange auth code for tokens'
  8. You will see an input box containing a refresh token

The refresh token is the equivalent of your long lived username/password, so this is what you'll hard code (or store someplace secure your app can retrieve it).

When you need to access Google Spreadsheets, you will call

POST https://accounts.google.com/o/oauth2/token
content-type: application/x-www-form-urlencoded
client_secret=************&grant_type=refresh_token&refresh_token=1%2xxxxxxxxxx&client_id=999999999999.apps.googleusercontent.com

which will return you an access token

{
  "access_token": "ya29.yyyyyyyyyyyyyyyyyy", 
  "token_type": "Bearer", 
  "expires_in": 3600
}

Put the access token into an http header for whenever you access the spreadsheet API

Authorization: Bearer ya29.yyyyyyyyyyyyyyyyy

And you're done

OTHER TIPS

Pinoyyid has indeed provided wonderful help. I wanted to follow up with Python code that will allow access to a Personal (web-accessible) Google Drive.

This runs fine within the Google App Engine (as part of a web app) and also standalone on the desktop (assuming the Google App Engine SDK is installed on your machine [available from: https://developers.google.com/appengine/downloads]).

In my case I added https://www.googleapis.com/auth/drive scope during Pinyyid's process because I wanted access to all my Google Drive files.

After following Pinoyyid's instructions to get your refresh token etc., this little Python script will get a listing of all the files on your Google drive:

import httplib2
import datetime
from oauth2client.client import OAuth2Credentials
from apiclient.discovery import build

API_KEY = 'AIz...'       # from "Key for Server Applications" from "Public API Access" section of Google Developers Console
access_token = "ya29..." # from Piinoyyid's instructions
refresh_token = "1/V..." # from Piinoyyid's instructions
client_id = '654....apps.googleusercontent.com' # from "Client ID for web application" from "OAuth" section of Google Developers Console
client_secret = '6Cl...' # from "Client ID for web application" from "OAuth" section of Google Developers Console
token_expiry = datetime.datetime.utcnow() - datetime.timedelta(days=1)
token_uri = 'https://accounts.google.com/o/oauth2/token'
user_agent = 'python urllib (I reckon)'

def main():
    service = createDrive()
    dirlist = service.files().list(maxResults=30)
    print 'dirlist', dirlist
    result = dirlist.execute()
    print 'result', result

def createDrive():
    credentials = OAuth2Credentials(access_token, client_id, client_secret, refresh_token, token_expiry, token_uri, user_agent)
    http = httplib2.Http()
    http = credentials.authorize(http)
    return build('drive', 'v2', http=http, developerKey=API_KEY)

main()

I'm grateful to all who have provided the steps along the way to solving this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top