Authenticating with Google API using AccountManager
-
15-11-2019 - |
Question
I've been struggling with this for a couple days now. I'm trying to make calls to Google Calendar using authentication via Android's AccountManager
. I retrieve an auth token using the usual method:
AccountManager manager = AccountManager.get(this);
String authToken = manager.getAuthToken(account, AUTH_TOKEN_TYPE, true, null, null).getResult().getString(AccountManager.KEY_AUTHTOKEN);
And then, with that token, I create a Calendar
instance like this:
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleAccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(accessToken);
Calendar calendar = Calendar.builder(transport, jsonFactory).setApplicationName("MyApp/1.0").setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
@Override
public void initialize(JsonHttpRequest request) {
CalendarRequest calendarRequest = (CalendarRequest) request;
calendarRequest.setKey(API_KEY);
}
}).setHttpRequestInitializer(accessProtectedResource).build();
However, when I make API calls using this, I receive the 401 Unauthorized
error seen below. Note that I have included code to invalidate expired auth tokens, so I don't believe that's the problem here.
com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError"
} ],
"message" : "Invalid Credentials"
}
Any thoughts on what I might be doing wrong?
Solution
Yes this is possible. Once you have a handle on the Google account (as you described), you just need to request an auth token from the AccountManager for the GData service.
If the android device already has an auth token (for the particular GData service you're trying to access), it will be returned to you. If not, the AccountManager will request one and return it to you. Either way, you don't need to worry about this as the AccountManager handles it.
In the following example, I am using the Google Spreadsheets API:
ArrayList<Account> googleAccounts = new ArrayList<Account>();
// Get all accounts
Account[] accounts = accountManager.getAccounts();
for(Account account : accounts) {
// Filter out the Google accounts
if(account.type.compareToIgnoreCase("com.google")) {
googleAccounts.add(account);
}
}
AccountManager accountManager = AccountManager.get(activity);
// Just for the example, I am using the first google account returned.
Account account = googleAccounts.get(0);
// "wise" = Google Spreadheets
AccountManagerFuture<Bundle> amf = accountManager.getAuthToken(account, "wise", null, activity, null, null);
try {
Bundle authTokenBundle = amf.getResult();
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
// do something with the token
InputStream response = sgc.getFeedAsStream(feedUrl, authToken, null, "2.1");
}
AND
Please have a look at the sample code in the google data api. The important thing to do after authentication is to call GoogleHeaders.setGoogleLogin(String).
I hope this helps.
OTHER TIPS
Ran into a similar issue myself. I found that I need to set the xoauth_requestor_id in the unknown keys list ( reference : http://www.yenlo.nl/2011/google-calendar-api-v3-and-2lo/ )
This worked for me:
com.google.api.services.calendar.Calendar.CalendarList.List list = calendar.calendarList().list();
//Set the requestor id
list.getUnknownKeys().put("xoauth_requestor_id", "user@gmail.com");
After this the API calls went thru.
I wish there was a explanation as to why the requestor id is needed. Can someone explain?