Hello Alain!
Thanks for your answer!
> If you want to use the OAuth 2.0 token from the Tasks API to access Calendar
> data
No, I want to do a different thing.
My application needs data from both Google Tasks and Google Calendar.
And now I attempt to implement this:
1) The user of my application logs in.
2) He authorizes my application to access Google data. At the end of
this process my application gets a refresh token.
3) From now, my application can exchange the long-lived refresh token
for a short-lived access token, and then access user's data.
The application can do this in the background (without interaction
with the user) as long as the refresh token has not been revoked by
the user or my application.
* * *
Steps 1 and 2 occur
a) in a web application,
b) in interaction with the user and
c) only once.
Step 3 occurs in a background application (like a daemon) several
times a day.
Below I call steps 1 and 2 "interactive part" and step 3 - "server
part".
* * *
Now I have implemented this scheme for Google Tasks API and it works.
Now I want to implement this for Google Calendar. Up to now I have
created this:
Interactive part
First I redirect the user to the Google Calendar authorization page
(the one with "Allow/deny access"):
> try {
> oauthParameters = new GoogleOAuthParameters();
> oauthParameters.setOAuthConsumerKey("myapp.com");
> oauthParameters.setScope(SCOPE_CALENDAR);
> oauthParameters.setOAuthCallback(REDIRECT_URL);
>
> privKey = getPrivateKey();
>
> oauthHelper =
> new GoogleOAuthHelper(new OAuthRsaSha1Signer(privKey));
> oauthHelper.getUnauthorizedRequestToken(oauthParameters);
>
> TPTApplication
> .getCurrentApplication()
> .getMainWindow()
> .open(new ExternalResource(oauthHelper
> .createUserAuthorizationUrl(oauthParameters)),
> "_top");
>
> } catch (final OAuthException exception) {
> LOGGER.error("", exception);
> }
When the user has allowed my application to access his/her Google
Calendar data, he is redirected to my application.
In the querystring, there are oauth_verifier and oauth_token
parameters.
>From them, I get the token secret:
> oauthHelper.getOAuthParametersFromCallback(oauthQueryString,
> oauthParameters);
> LOGGER.debug("Token secret: '{}'",
> oauthParameters.getOAuthTokenSecret());
>
Note that oauthHelper and oauthParameters are exactly the same Java
objects as in the first code snipped (i. e. I create them there and re-
use them, when the user returns to my page).
At the end of the interactive part I have 3 pieces of information:
1) OAuth verifier
2) Token
3) Token secret
Server part
In the server part, I use them to get access to Google Calendar data:
> @Test
> public void testCalendar() {
> final HttpTransport httpTransport = new NetHttpTransport();
> final JacksonFactory jsonFactory = new JacksonFactory();
>
> try {
> PrivateKey privKey = getPrivateKey();
> final OAuthRsaSha1Signer signer = new OAuthRsaSha1Signer(privKey);
>
>
> GoogleOAuthParameters oauthParameters = new
> GoogleOAuthParameters();
> oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
>
> GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(signer);
>
>
>
> oauthParameters.setScope("http://www.google.com/calendar/feeds/");
>
> oauthParameters.setOAuthVerifier("toy8IMW6sInKDTjPxfy5zMFD");
>
> oauthParameters.setOAuthToken("4/Oj-Q3isN3rz8mvJbgAkaIHGkL882");
> oauthParameters.setOAuthTokenSecret("xQ8-9M22ZSdITuaTFAhPpcoA");
>
> oauthHelper.getAccessToken(oauthParameters);
>
>
> final CalendarService calendarService =
> new CalendarService("myapp.com");
>
> calendarService
> .setOAuthCredentials(oauthParameters, signer);
>
> LOGGER.debug("calendarService: {}", calendarService);
>
> final URL feedUrl =
> new URL(
>
> "https://www.google.com/calendar/feeds/default/allcalendars/full");
> final CalendarFeed resultFeed =
> calendarService.getFeed(feedUrl, CalendarFeed.class);
>
> LOGGER.debug("resultFeed: {}", resultFeed);
>
> LOGGER.debug("Your calendars:");
>
> CalendarEntry pccCalendar = null;
> for (int i = 0; (i < resultFeed.getEntries().size())
> && (pccCalendar == null); i++) {
> final CalendarEntry entry = resultFeed.getEntries().get(i);
>
> LOGGER.debug(entry.getTitle().getPlainText());
> }
>
> } catch (final IOException exception) {
> LOGGER.error("", exception);
> Assert.fail(exception.getMessage());
> } catch (final OAuthException exception) {
> LOGGER.error("", exception);
> Assert.fail(exception.getMessage());
> } catch (final ServiceException exception) {
> LOGGER.error("", exception);
> Assert.fail(exception.getMessage());
> }
> }
In the calls
> oauthParameters.setOAuthVerifier("toy8IMW6sInKDTjPxfy5zMFD");
>
> oauthParameters.setOAuthToken("4/Oj-Q3isN3rz8mvJbgAkaIHGkL882");
> oauthParameters.setOAuthTokenSecret("xQ8-9M22ZSdITuaTFAhPpcoA");
I use the verifier, token and the token secret, which I got from the
user in the interactive part (steps 1 and 2).
* * *
When I
a) do the interactive part (steps 1 and 2) and
b) then run the server-sided test case (step 3),
for the first time, it works.
But when I run the test case second (third, fourth, n-th) time, I get
the exception
> com.google.gdata.client.authn.oauth.OAuthException: Error getting HTTP
> response
> at
> com.google.gdata.client.authn.oauth.OAuthHttpClient.getResponse(OAuth
> HttpClient.java:76) ~[gdata-core-1.0.jar:na]
> at
> com.google.gdata.client.authn.oauth.OAuthHttpClient.getResponse(OAuth
> HttpClient.java:44) ~[gdata-core-1.0.jar:na]
> at
> com.google.gdata.client.authn.oauth.OAuthHelper.getAccessToken(OAuthH
> elper.java:559) ~[gdata-core-1.0.jar:na]
> at com.myapp.test.serversidedoauth.TestServerSidedOAuth.testCa
> lendar(TestServerSidedOAuth.java:133) ~[test-classes/:na]
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> ~[na:1.6.
> 0_23]
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
> java:39) ~[na:1.6.0_23]
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
> sorImpl.java:25) ~[na:1.6.0_23]
> at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_23]
> at
> org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(Framework
> Method.java:44) [junit-4.8.2.jar:na]
> at
> org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCal
> lable.java:15) [junit-4.8.2.jar:na]
> at
> org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMe
> thod.java:41) [junit-4.8.2.jar:na]
> at
> org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMet
> hod.java:20) [junit-4.8.2.jar:na]
> at
> org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4Cla
> ssRunner.java:79) [junit-4.8.2.jar:na]
> at
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRun
> ner.java:71) [junit-4.8.2.jar:na]
> at
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRun
> ner.java:49) [junit-4.8.2.jar:na]
> at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
> [junit-4.
> 8.2.jar:na]
> at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
> [juni
> t-4.8.2.jar:na]
> at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
> [ju
> nit-4.8.2.jar:na]
> at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
> [juni
> t-4.8.2.jar:na]
> at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
> [jun
> it-4.8.2.jar:na]
> at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
> [junit-4.8.
> 2.jar:na]
> at
> org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.
> java:62) [surefire-junit4-2.4.3.jar:2.4.3]
> at
> org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTes
> tSet(AbstractDirectoryTestSuite.java:140) [surefire-api-2.4.3.jar:2.4.3]
> at
> org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(Ab
> stractDirectoryTestSuite.java:127) [surefire-api-2.4.3.jar:2.4.3]
> at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
> [surefire-a
> pi-2.4.3.jar:2.4.3]
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> ~[na:1.6.
> 0_23]
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
> java:39) ~[na:1.6.0_23]
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
> sorImpl.java:25) ~[na:1.6.0_23]
> at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_23]
> at
> org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(Su
> refireBooter.java:345) [surefire-booter-2.4.3.jar:2.4.3]
> at
> org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.j
> ava:1009) [surefire-booter-2.4.3.jar:2.4.3]
> Caused by: java.io.IOException: Server returned HTTP response code: 400 for
> URL:
> https://www.google.com/accounts/OAuthGetAccessToken?scope=http%3A%2F%2Fwww.goog
> le.com%2Fcalendar%2Ffeeds%2F&oauth_nonce=5563771650945&oauth_signature_method=RS
> A-SHA1&oauth_consumer_key=myapp.com&oauth_token=4%2FOj-Q3isN3rz8mvJbgAkaIHGkL882
> &oauth_verifier=toy8IMW6sInKDTjPxfy5zMFD&oauth_timestamp=1310285997&oauth_signat
> ure=nvZ%2FLIxaE%2FKGHS1kWTpIlL9sfV5mvaN4%2B755h1wIbUMiXFylnKQMXTGqzSZNkFtWkQGgVf
> tl9xCFaDAHxjPxksHytHdpCW%2BWj146UkQH0L2g8W57y97zI9DLArB82rBWF%2BEeyU%2Bminr5TpJH
> x%2BQMZ6pAx6sih5rIuTLskbi8mqc%3D
> at
> sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLCon
> nection.java:1441) ~[na:1.6.0_23]
> at
> sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Http
> sURLConnectionImpl.java:234) ~[na:1.6]
> at
> com.google.gdata.client.authn.oauth.OAuthHttpClient.getResponse(OAuth
> HttpClient.java:66) ~[gdata-core-1.0.jar:na]
> ... 30 common frames omitted
>
What I want to achieve is that the server-sided part runs not just
once, but as
many times as I want (until the user or I revoke access).
What part of my code is wrong?
Thanks in advance
Dmitri
On Jul 6, 6:29 pm, Alain Vongsouvanh <[email protected]> wrote:
> Hello Dmitri,
>
> You are getting an OAuth 2.0 token for the Tasks API and are using the same
> token to access the Calendar API using the OAuth 1.0 protocol. The error is
> expected as those tokens are not compatible.
>
> If you want to use the OAuth 2.0 token from the Tasks API to access Calendar
> data, you can do something like this:
>
> service.setHeader("Authorization", "OAuth " + this.oauthAccessToken);
>
> Please, do not forget to ask the Calendar API scope when requesting the
> OAuth 2.0 token:
>
> String scope =
> "https://www.googleapis.com/auth/taskshttps://www.google.com/calendar/feeds";
>
> However, you will have to handle the "token expired" exception and refresh
> the token manually as the Google Data client library doesn't natively
> support OAuth 2.0.
>
> One last thing, please use SSL (https) over non-SSL (http) whenever possible
> for accessing Google APIs.
>
> Best,
> Alain
>
>
>
>
>
>
>
>
>
> On Fri, Jul 1, 2011 at 1:46 PM, DP <[email protected]> wrote:
> > Hello!
>
> > Can the cause of the problem be that I attempt to access two different
> > Google services (Tasks and Calendar) with different scopes using ONE
> > access token?
>
> > TIA
>
> > Dmitri
>
> > On Jul 1, 5:47 pm, DP <[email protected]> wrote:
> > > Hello!
>
> > > I get the error
>
> > > com.google.gdata.util.AuthenticationException: Unknown authorization
> > > header
> > > at
>
> > com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:
> > > 600) ~[gdata-core-1.0.jar:na]
> > > at
>
> > com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:
> > > 563) ~[gdata-core-1.0.jar:na]
> > > at
>
> > com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:
> > > 552) ~[gdata-core-1.0.jar:na]
> > > at
>
> > com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:
> > > 530) ~[gdata-core-1.0.jar:na]
> > > at
>
> > com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:
> > > 535) ~[gdata-core-1.0.jar:na]
>
> > > when trying to access the Google Calendar data via their API.
>
> > > Here is what happens before that error.
>
> > > 1) I authenticate with Google:
>
> > > final AccessTokenResponse response =
> > > new GoogleAuthorizationCodeGrant(httpTransport,
> > > jsonFactory,
> > > clientId, clientSecret, authorizationCode,
> > > redirectUrl).execute();
>
> > > final GoogleAccessProtectedResource accessProtectedResource =
> > > new GoogleAccessProtectedResource(
> > > response.accessToken, httpTransport, jsonFactory,
> > > clientId, clientSecret,
> > > response.refreshToken);
>
> > > LOGGER.debug("response.accessToken: {}", response.accessToken);
>
> > > this.oauthAccessToken = response.accessToken;
>
> > > ...
>
> > > 2) I read some data via the tasks API:
>
> > > this.service =
> > > new Tasks(httpTransport, accessProtectedResource,
> > > jsonFactory);
> > > this.service.setApplicationName(this.applicationName);
>
> > > This seems to work.
>
> > > 3) Then I try to read data from the Google Calendar API:
> > > final OAuthHmacSha1Signer signer = new
> > > OAuthHmacSha1Signer();
>
> > > final GoogleOAuthParameters oauth = new
> > > GoogleOAuthParameters ();
>
> > > oauth.setOAuthConsumerKey("myapp.com");
> > > oauth.setOAuthConsumerSecret(CLIENT_SECRET); // Client
> > > secret from "Google API access" page, "Client secret" entry
> > > oauth.setOAuthToken(this.oauthAccessToken); // Access
> > > token from step 1
> > > oauth.setOAuthTokenSecret(aAuthorizationCode);
> > > // aAuthorizationCode is taken from the callback URL.
> > > // Forhttp://
> > myapp.com/oauth2callback?code=4/uy8Arb4bhRPwWYSr3QwKPt9lIZkt
> > > // aAuthorizationCode is equal to "4/
> > > uy8Arb4bhRPwWYSr3QwKPt9lIZkt" (without quotes)
>
> > > oauth.setScope(SCOPE_CALENDAR); //
> >https://www.google.com/calendar/feeds/
>
> > > final CalendarService calendarService =
> > > new CalendarService(APPLICATION_NAME);
>
> > > calendarService
> > > .setOAuthCredentials(oauth, signer);
>
> > > LOGGER.debug("calendarService: {}", calendarService);
>
> > > final URL feedUrl =
> > > new URL(
> > > "http://www.google.com/calendar/feeds/
> > > default/allcalendars/full");
> > > final CalendarFeed resultFeed =
> > > calendarService.getFeed(feedUrl,
> > > CalendarFeed.class);
>
> > > At the last line (calendarService.getFeed...) the aforementioned
> > > exception occurs.
>
> > > I have following questions:
>
> > > 1) Is my call
>
> > > oauth.setOAuthConsumerKey
>
> > > correct?
>
> > > I. e. is the "consumer key" equal to "Product name" in the Google API
> > > console, or to "Client ID" field (value is something like
> > > 42912397129473.apps.googleusercontent.com)
>
> > > 2) Is the setOAuthTokenSecret correct? I. e. is it the code that I
> > > get, when Google redirects the user back to my app?
>
> > > 3) If questions 2 and 3 were answered with yes, what else can be the
> > > cause of my problem?
>
> > > Thanks
>
> > > Dmitri
>
> > > P. S.: Previously, I could access Google calendar with simple access
> > > (i. e. with Google user name and password). However, this is not an
> > > option now because users of my app will not want to give away their
> > > Google password.
>
> > > P. P. S.: You can earn StackOverflow reputation points by answering
> > > the question there:
> >http://stackoverflow.com/questions/6550143/google-calendar-api-and-oa...
>
> > --
> > You received this message because you are subscribed to the Google
> > Groups "Google Calendar Data API" group.
> > To post to this group, send email to
> > [email protected]
> > To unsubscribe from this group, send email to
> > [email protected]
> > For more options, visit this group at
> >http://code.google.com/apis/calendar/community/forum.html
>
> --
> Alain Vongsouvanh
--
You received this message because you are subscribed to the Google
Groups "Google Calendar Data API" group.
To post to this group, send email to
[email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://code.google.com/apis/calendar/community/forum.html