Android Coding Example: Authenticating with ClientLogin and using the Google Reader API
Introduction
Let me start by saying that I would of killed for an article on this a few months ago when I started writing Subscriber.
The Google Reader API is well documented out there on the Internet, but getting access to actual Java code examples is something else.
I spent many hours with Chrome, Curl, Java and Wireshark working out how to converse with Google Reader and eventually cracked it.
Anyway, moving swiftly on.. In this article I will demonstrate (with Java code examples) how to authenticate with Google
Reader and how to use certain parts of its API.
Google Reader Authentication
To use Google Reader’s API you need to authenticate using “ClientLogin”.
ClientLogin is intended for installed (desktop/mobile) applications. With this method of authentication, the application using Google Data APIs directly handles the username and password of the user.An authentication request for ClientLogin takes a username, password, and service name as form post variables and yields a response with several tokens – one of which can be used to make requests to the Google Data service.
The first part of the process is a POST (with some data) to https://www.google.com/accounts/ClientLogin . The response of which is;
SID=DQAAAHYBADCv2pSv7nflacDNwz3zEDUGtrSvNVDcpkSfddi77b3U5sEaHmP8YLWhmA36F9rk85mL8J5dqo4apn0T1vKz0fPGI9Xtnuet6cuE2ZzYvrNIwbSC_HjTqF4zudNQnnlDuD2wqZT-g1qXI8KhGAQZV4NexHZoQPlabTsGuRZeIBxj1ALSID=EUBBBIaBADCl-kNxvRVmcQghpt3cqSMfEooKR9flLOUZqwgP9OrZS83gse-KSdTNeXhxsET7FYenDhceP9lIPOmesH-t9qh-AWUHjjMdZEbUNeF9mWyzln6Z-FajaiG-cVFkqW0ZJ8ZbnCP30xXj6xFK6QxaAcqy_9Pej8jhEnxS9E61ftQGPgAuth=EUBBIacAAADK-kNxvRVmcQghpt3cqSMfEooLNMflLNIQqwgP9OrZS83gs-KSdTNeXhxsET7FYePWmaD8Vsy1V4LSUGMUP48Je2TO8OcjBj6HgAtPhiZeX-gKDfagZDK44j4n-Tkb44nhOnp2_QPSnBj3Z2vYwOEDjjG3Q53aQVC2132JKOuGh
We next need to get a Token. In order to get a “Token” we need to use the Auth key. The big long string after the “Auth=”. This requires a GET (with data) to http://www.google.com/reader/api/0/token. This returns a Token similar to “57LiuCxazGzwl6cVPAGnMg“.
Once you have this Token you are able to make API calls to Google Reader. I suggest looking at the further reading for more information on the Google Reader API.
How to connect to Google Reader and parse its results
When I first started coding Subscriber, I was using the inbuilt Java net libraries to converse with http. Once I started
having to work out how to parse html responses I found a fantastic class called JSOUP written by
With this class you are able to do GETS and POSTS with ease and parse HTML with very little work. I urge you to check out
the JSOUP site and get stuck in.
Onto the code!
Pre-requisites:
Eclipse IDE
Latest JSOUP Jar file added to your project build path
My Func_String.jar file added to your project build path (available here)
Pre-requisite steps:
- Download the latest jsoup jar file
- Open Eclipse and right-click your project and select Properties
- Select Java Build Path
- Select Libraries
- Select Add Jars
- Find the download JSOUP Jar and select OK
- Select OK
The JSOUP class is now available to import into your project.
Code examples:
Variables
private static final String _AUTHPARAMS = "GoogleLogin auth="; private static final String _GOOGLE_LOGIN_URL = "https://www.google.com/accounts/ClientLogin"; private static final String _READER_BASE_URL = "http://www.google.com/reader/"; private static final String _API_URL = _READER_BASE_URL + "api/0/"; private static final String _TOKEN_URL = _API_URL + "token"; private static final String _USER_INFO_URL = _API_URL + "user-info"; private static final String _USER_LABEL = "user/-/label/"; private static final String _TAG_LIST_URL = _API_URL + "tag/list"; private static final String _EDIT_TAG_URL = _API_URL + "tag/edit"; private static final String _RENAME_TAG_URL = _API_URL + "rename-tag"; private static final String _DISABLE_TAG_URL = _API_URL + "disable-tag"; private static final String _SUBSCRIPTION_URL = _API_URL + "subscription/edit"; private static final String _SUBSCRIPTION_LIST_URL = _API_URL + "subscription/list";
Imports
import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;
Getting a Google Authentication Key – Returns an authentication key as a string
/**
* Returns a Google Authentication Key
* Requires a Google Username and Password to be sent in the POST headers
* to http://www.google.com/accounts/ClientLogin
*
* @param GoogleGoogle_Username Google Username
* @param Google_Password Google Password
* @return Google authorisation token
* @see getGoogleToken
*/public static String getGoogleAuthKey(String _USERNAME, String _PASSWORD) throws UnsupportedEncodingException, IOException { Document doc = Jsoup.connect(_GOOGLE_LOGIN_URL) .data("accountType", "GOOGLE", "Email", _USERNAME, "Passwd", _PASSWORD, "service", "reader", "source", "<your app name>") .userAgent("<your app name>") .timeout(4000) .post(); // RETRIEVES THE RESPONSE TEXT inc SID and AUTH. We only want the AUTH key. String _AUTHKEY = doc.body().text().substring(doc.body().text().indexOf("Auth="), doc.body().text().length()); _AUTHKEY = _AUTHKEY.replace( "Auth=","" ); return _AUTHKEY; }
Getting a Google Reader Token – Returns a Google token as a string
/**
* Returns a Google Token
* Requires a Google Username, Password and Auth key to be sent in the GET
* to http://www.google.com/reader/api/0/token
*
* @param Google_Username Google Username
* @param Google_Password Google Password
* @return Google authorisation token
* @see getGoogleAuthKey
*/public static String getGoogleToken(String _USERNAME, String _PASSWORD) throws UnsupportedEncodingException, IOException { Document doc = Jsoup.connect(_TOKEN_URL) .header("Authorization", _AUTHPARAMS + getGoogleAuthKey(_USERNAME,_PASSWORD)) .userAgent("<your app name") .timeout(4000) .get(); // RETRIEVES THE RESPONSE TOKEN String _TOKEN = doc.body().text(); return _TOKEN; }
Retrieving Google Reader User Info
/**
* Returns Google Reader User Info
* Requires a Google Username, Password and AUTH key to be sent in the POST
* to http://www.google.com/reader/api/0/user-info
*
* @param GoogleGoogle_Username Google Username
* @param Google_Password Google Password
* @return Google Reader User Info
* @see getGoogleToken
*/public static String getUserInfo(String _USERNAME, String _PASSWORD) throws UnsupportedEncodingException, IOException { Document doc = Jsoup.connect(_USER_INFO_URL) .header("Authorization", _AUTHPARAMS + getGoogleAuthKey(_USERNAME,_PASSWORD)) .userAgent("<your app name>") .timeout(4000) .get(); // RETRIEVES THE RESPONSE USERINFO String _USERINFO = doc.body().text(); return _USERINFO; }
Retrieving Google Reader User ID
/**
* Returns Google User ID
* Requires a Google Username and Password to be sent in the POST headers
* to http://www.google.com/accounts/ClientLogin
*
* @return Google User ID
* @see getGoogleToken, getGoogleAuthKey
*/public static String getGoogleUserID(String _USERNAME, String _PASSWORD) throws UnsupportedEncodingException, IOException { /* USERINFO RETURNED LOOKS LIKE * {"userId":"14577161871823252783", * "userName":"<username>","userProfileId":"<21 numeric numbers", * "userEmail":"<username>@gmail.com", * "isBloggerUser":true, * "signupTimeSec":1159535065} */ String _USERINFO = getUserInfo(_USERNAME, _PASSWORD); String _USERID = (String) _USERINFO.subSequence(11, 31); return _USERID; }
Retrieving Google Reader Tags – Returns an array of Tags (not starred or shared)
public static String[] getTagList(String _USERNAME, String _PASSWORD) { Log.d(_APP_TAG, "METHOD: getTagList()"); ArrayList<String> _TAGTITLE_ARRAYLIST = new ArrayList<String>(); String _TAG_LABEL = null; try { _TAG_LABEL = "user/" + getGoogleUserID(_USERNAME,_PASSWORD) + "/label/"; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Document doc = null; try { doc = Jsoup.connect(_TAG_LIST_URL) .header("Authorization", _AUTHPARAMS + getGoogleAuthKey(_USERNAME,_PASSWORD)) .userAgent("<your app name>") .timeout(6000) .get(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Elements links = doc.select("string"); for (Element link : links) { String tagAttrib = link.attr("name"); String tagText = link.text(); if(Func_Strings.FindWordInString(tagText, _TAG_LABEL)) { _TAGTITLE_ARRAYLIST.add(tagText.substring(32)); } } String[] _TAGTITLE_ARRAY = new String[_TAGTITLE_ARRAYLIST.size()]; _TAGTITLE_ARRAYLIST.toArray(_TAGTITLE_ARRAY); return _TAGTITLE_ARRAY; }
Retrieving Google Reader Subscriptions – Returns and array of Subscriptions
public static String[] getSubList(String _USERNAME, String _PASSWORD) throws UnsupportedEncodingException, IOException { ArrayList<String> _SUBTITLE_ARRAYLIST = new ArrayList<String>(); Document doc = Jsoup.connect(_SUBSCRIPTION_LIST_URL) .header("Authorization", _AUTHPARAMS + getGoogleAuthKey(_USERNAME,_PASSWORD)) .userAgent("<your app name>") .timeout(5000) .get(); Elements links = doc.select("string"); for (Element link : links) { String tagAttrib = link.attr("name"); String tagText = link.text(); _SUBTITLE_ARRAYLIST.add(tagText); } String[] _SUBTITLE_ARRAY = new String[_SUBTITLE_ARRAYLIST.size()]; _SUBTITLE_ARRAYLIST.toArray(_SUBTITLE_ARRAY); return _SUBTITLE_ARRAY; }
These methods can all be bundled into a class and a test class written to connect to Google Reader.
Example test class;
public static void main(String[] args) throws IOException { // Get Auth Key System.out.println(Func_JSOUP.getGoogleAuthKey(_USERNAME, _PASSWORD)); // Get Token System.out.println(Func_JSOUP.getGoogleToken(_USERNAME, _PASSWORD)); // Get UserID System.out.println(Func_JSOUP.getGoogleUserID(_USERNAME, _PASSWORD)); // Get Reader TAG TITLES String[] _TAG_TITLES = Func_JSOUP.getTagList(_USERNAME, _PASSWORD); for(int i = 0; i < _TAG_TITLES.length; i++){ System.out.println(_TAG_TITLES[i]); } // Get Reader SUBSCRIPTION TITLES String[] _SUB_TITLES = Func_JSOUP.getSubList(_USERNAME, _PASSWORD); for(int i = 0; i < _SUB_TITLES.length; i++){ System.out.println(_SUB_TITLES[i]); } }
I hope you have found this article useful for your project.
If you have anything further to share or wish to comment feel free to do so.
#1 by Ondra on October 15, 2010 - 1:26 am
Hello, thanks for nice Documentation. Google should hire you. Could you describe method, how to track another functions of Google Reader?
#2 by Carroll B. Merriman on November 23, 2010 - 6:22 pm
This is great stuff, thanks!
#3 by Rajat Gupta on September 9, 2011 - 11:35 am
very helpful
thanks alot who share this
#4 by Alex on October 23, 2011 - 5:16 am
Thanks for the code snippets. They helped a lot.
You might want to mention that you also need the Func_strings class, which can be downloaded from here: http://code.google.com/p/android-ced/source/browse/bbcbc/trunk/src/uk/co/chrisdadswell/bbcbc/Func_Strings.java
Alex
#5 by Kimi on December 28, 2011 - 10:09 pm
Hi,
can you please tell me how to retrieve a list of starred feeds?
Thanks a lot.
#6 by Vishal Kotcherlakota on January 29, 2012 - 4:14 am
This is a fantastic piece of information! I’m a little concerned about the password, though. Does the password itself get transmitted over HTTP in cleartext? :scared: