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?

Was it helpful?

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?

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