Adding OAuth2 to OpenSelfie

As in most things Internet, when you make them more secure, things get more complicated. A little while ago, photo uploads from OpenSelfie (our OpenSource Raspberry Pi AlaMode Photobooth) stopped working. It turns out that Google disabled “programmatic login” (e.g. with a username and password) from most of their apis, including the picasaweb api that we use to upload photos. Now the only thing that works is OAuth2, and it requires a little dance between a web browser signed into your google account, and granting of credentials for your application.

Diagram from the google developers site

Diagram from the google developers site

I had a real hard time figuring out how it all works until I found this link:

https://groups.google.com/forum/#!topic/google-picasa-data-api/4meiAJ40l3E

There were bits of information missing, and a couple of errors but I eventually figured it out. The new code is in boothcam.py in a procedure called OAuth2Login, which takes a pointer to a secrets json file (more on this below), a credentials store file (where the authenticated credentials are cached for you, and the user’s email address.

There’s also a standalone version for listing Album ids (useful for configuring a new album for an event in listalbums.py

You’ll need to install the latest google python api:

$ sudo pip install --upgrade google-api-python-client

If this is your first time, or you are looking to steal this code for another project, you’ll need some other python libraries, most notably

$ sudo apt-get install python-gdata
def OAuth2Login(client_secrets, credential_store, email):
 scope='https://picasaweb.google.com/data/'
 user_agent='picasawebuploader'

 storage = Storage(credential_store)
 credentials = storage.get()
 if credentials is None or credentials.invalid:
   flow = flow_from_clientsecrets(client_secrets, scope=scope, redirect_uri='urn:ietf:wg:oauth:2.0:oob')
   uri = flow.step1_get_authorize_url()
   webbrowser.open(uri)
   code = raw_input('Enter the authentication code: ').strip()
   credentials = flow.step2_exchange(code)

 if (credentials.token_expiry - datetime.utcnow()) < timedelta(minutes=5):
   http = httplib2.Http()
   http = credentials.authorize(http)
   credentials.refresh(http)

 storage.put(credentials)

 gd_client = gdata.photos.service.PhotosService(source=user_agent,
 email=email,

 additional_headers={'Authorization' : 'Bearer %s' % credentials.access_token})

You can see it creates a flow and asks google for credentials using your secrets file. (note that this is not checked in as you could use up my api credits. You;ll need to create your own.) It then spins up a web browser, makes sure you are logged in to your google account (the email address you configured OpenSelfie with) and asks your permission.

It will then give you a code to enter into OpenSelfie. I had troiuble cutting and pasting from the default web browser so I installed luakit, and made it the default browser

$ sudo update-alternatives --config x-www-browser

Creating your own API keys with the Google Developer console

Head on over to the Google Developer console and create a project for your OpenSelfie

Google-dev-step1

The name here doesn’t really matter. I just used OpenSelfie.

Next, click on your project and click on Credentials under API’s and auth.

If you haven’t already, you;ll need to configure the OAuth consent screen.

The only thing you really need to do is specify the  Product Name.

OAuth Consent screenYou’ll want to “Add Credentials/OAuth 2.0 client ID” Note: you don’t have to explicitely enable any additional APIs, as we are dealing with basic authentication and authorization here which is used by every API, and the photo apis haven’t been explicitly added to the console.

google-dev-step3

Next you specify the type “Other” and I named it Installed. Most of the instructions I saw seemed to imply there used to be a type called Installed. I’m not sure it’s critical that this name be here, but I used it to be safe. Click Create.

google-dev-step4

Now you’ll see it in your list of credentials for this app.

google-dev-step5

Click OK, and then click on the “Installed” credential. When that’s open, click on Download JSON. It will download a file with a name like client_secret_90328409238409238……json

google-dev-step6-download

rename this file OpenSelfie.json and put it in the OpenSelfie/scripts directory.

Configuring OpenSelfie

Start up OpenSelfie in a terminal window:

cd OpenSelfie/scripts
python ./photobooth_gui.py

If you’ve already configured your OpenSelfie, when it tries to login to google, it will find it doesn’t have credentials and then start the flow to create them. Your web browser will pop up, you should sign in to google, (with the same email address you configured.) and then it will ask you if OpenSelfie  can manipulate your photos.

Permission

Click on Allow, and then it will display a box with a long string of numbers and letters. Cut and paste that into the console window where it says “Enter the Authentication Code.” hit enter, and if all is well it will snap a photo and upload it to the album you have previously configured (or fail if you haven’t set it yet.)

paste-code

Fortunately, you only have to do this once! After this it will remember the credentials and periodically refresh them. The cached credentials are stored in a file called credentials.dat, so if you delete it, you’ll have to do the web dance again, as long as your json file is still there.

Conclusion?

Well, it seems to me that Google is trying to be a good security player, at the cost of ease of use. It seems that it’s very difficult to interact with devices with a limited UI (they suggest printing URLs and having them typed into another device). Fortunately we’re working with a full Raspberry Pi so it can all be done on the same machine. I’m sure the UI can be finessed, and if you do fork the project and make improvements, please make pull requests!

Leave a Reply