Update
If I were to do this today, I would probably use Google's SDK for Java and JavaLink, which would allow for a better solution. Some have asked me why I said that we have to involve the browser to do it in Mathematica, I was not clear on this point. The reason is that no ready made implementation of the required RSA SHA-256 encryption exists, so one has to implement that first if one wants to do it without using other languages or tools.
Preamble
From what I can tell, it's not possible to authorize with Google Data without involving the browser at some point. Among the different oAuth 2.0 flows that Google offers, I find the flow intended for devices the most suitable one for integration with Mathematica.
In essence, it works like this:
- The user visits the API console and registers his application. Google provides the user with a "client ID" and a "client secret".
- The application sends a request using the client ID. This request includes information about what kind of privileges the application needs.
- Google returns a code. When the user visits a certain URL and enters the code he will be able to review the list of privileges that the application requests. He then has to click a button to authorize the application to retrieve such information as is granted by those privileges.
- The application pings Google regularly to find out whether it has been authorized. At the moment that it's been authorized, Google returns a so called "access token" which can be used to send requests to the Google Data APIs.
Authorization with Mathematica
Since you cannot authorize once and be done with it (well... see "words of warning" about refresh tokens), but rather have to authorize every time you need to use the APIs, it's important that the process of authorization is not too cumbersome. I've implemented my solution as a package with a graphical user interface to make it as smooth as possible. Here's how it looks:

The workflow mirrors the list in the preamble. At first, only the top form will be shown. Upon sent request, the two bottom boxes will appear. As the user visits the verification URL and enters the user code, Google will authorize the application. The package pings Google at the interval recommended by Google, and when the application is authorized the bar stops moving and the text changes, as can be seen, to "We're now authorized."
At this point, we may acquire the access token like this:
GoogleOAuthAccessKey[]
access-key...
Installing the package
Download the package
Put it somewhere and use Get
(aka <<
):
<< "~/Documents/Mathematica/GOAuth.m"
Start the process using
GoogleOAuth[]
Words of warning
- The package does not attempt to deal with any errors that may arise. If it does not work, the best thing you can do is to restart the kernel and try again and make sure you have your credentials absolutely right.
- The time expiration on an access token appears to be, at the time of writing, one hour. If you need to use the API for prolonged periods of time, the best way to keep the session alive is not authorize manually over and over. Rather, you want to use refresh tokens. I didn't implement this, but those who have such needs can easily extend the package!
About the technology behind the curtain
I'd like to share some of the code, which is not related to the GUI, to shine some light on the process. For those who don't want to use the GUI and those who wants to understand how it works.
The first call to acquire the user code looks like this:
data = URLFetch[
"https://accounts.google.com/o/oauth2/device/code",
Method -> "POST",
"Parameters" -> {
"client_id" -> clientID,
"scope" -> scope
}
];
{deviceCode, expiresIn, interval, userCode,
verificationURL} = {"device_code", "expires_in", "interval",
"user_code", "verification_url"} /. ImportString[data, "JSON"];
As you can see, the data is returned as a JSON string. This goes for all Google Data API responses, so it's good to be aware of.
This request will check if we've been authorized:
tokens = URLFetch["https://accounts.google.com/o/oauth2/token",
Method -> "POST",
Parameters -> {
"client_id" -> clientID,
"client_secret" -> clientSecret,
"code" -> deviceCode,
"grant_type" -> "http://oauth.net/grant_type/device/1.0"
}
];
{accessToken, tokenType, accessExpiresIn, idToken,
refreshToken} = {"access_token", "token_type", "expires_in",
"id_token", "refresh_token"} /. ImportString[tokens, "JSON"];
If we haven't been authorized, the response will contain none of that information. Instead, it will only contain the element "error". The package looks for this to determine whether we've been authorized or not. The package keeps making this request every five seconds, as is currently recommended by Google, until we've been authorized.
Scopes and an example query
This query will obtain information about the user account:
URLFetch["https://www.googleapis.com/oauth2/v1/userinfo?access_token=" <> accessToken]
Whether or not we're allowed to request this information depends on what scope/privileges we requested to begin with. A suitable scope for this request is
https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
I will not delve into the specifics of scopes. I will not attempt to implement the Google Data Spreadsheet API, either. That way, this answer is agnostic as to which Google Data API is to be used. This package and this answer provides the first step of how to authorize with Google Data using Mathematica, for all the rest the official Google documentation should be used.
It has recently, long after I wrote this answer, come to my attention that using the "device flow" as this method does is currently not allowed for all Google APIs. So if it doesn't work for you with the specific API you had in mind, try to search on Google to see if other have also had problem while using the device flow for authorization.
URLFetch
, the key my package gives you and the URLs that you can find on this page if you select "protocol" for the samples: developers.google.com/google-apps/spreadsheets $\endgroup$google docs upload my_contacts.csv # Upload a CSV file, automatically converted to a spreadsheet.
$\endgroup$