Announcement Announcement Module
Collapse
No announcement yet.
Where is the Google refreshToken? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Where is the Google refreshToken?

    Hi,

    When I create a connection for Google, I keep getting a null value for the refreshToken. Isn't this supposed to be supplied?

    Marc

  • #2
    Since the Spring Social Google project is a community project, I've not spent much time with it, but looking at https://github.com/guznik/spring-soc...2Template.java, it appears that the refresh token is being gathered as part of the connection process. So, if it's null then I'd wonder if Google is actually sending back a null or if the field has a different name than what's in the code and Google's own documentation. The best way to do that is either to setup some sort of proxy between your app and Google or to manually perform the OAuth 2 dance and see what the response looks like. (That's one of the nice things about OAuth 2; you can do the entire dance manually using a web browser and curl to see how things behave.)

    Comment


    • #3
      Ok, finally figured out that in order to also receive the refreshtoken, the oauth request url has to contain a parameter
      access_type=offline

      Any suggestions on how to realize this?

      Comment


      • #4
        Yes, I see that in Google's documentation. Kinda goofy, but I guess that's how they work.

        You can set additional parameters by providing a connect interceptor and setting whatever extra parameters you need in the preConnect() method. For example:

        Code:
        public void preConnect(ConnectionFactory<S> connectionFactory, MultiValueMap<String, String> parameters, WebRequest request) {
            parameters.set("access_type", "offline");
        }
        Note that I just hacked this code into the forum and it has not been tested.

        Comment


        • #5
          Alternatively, you might be able to subclass GoogleOAuth2Template and override the buildAuthorizeUrl() method to tack on the parameter....something like this:

          Code:
          public String buildAuthorizeUrl(GrantType grantType, OAuth2Parameters parameters) {
              return super.buildAuthUrl(authorizeUrl, grantType, parameters) + "&access_type=offline";
          }
          Again, that was just hacked into the forum, so no guarantees on whether or not it will work.

          Comment


          • #6
            Awesome, thanks!

            Comment


            • #7
              Doesn't seem to be working

              It doesn't seem to be working although I can see the parameter being added to the oauth url.

              Funny thing is also that I'm not getting the Google Allow popup screen. It opens and closes immediately and just automatically allows me. Also if I logout before I do this, I get the login page in the popup and after login, it doesn't present me with the access types I'm requesting, but just grants it (without giving me the refreshToken).

              The access scope I'm asking for is
              https://www.google.com/m8/feeds/ https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo#email https://www.googleapis.com/auth/plus.me

              (after completing the connect request I can interact with the API just fine.)

              Comment


              • #8
                FYI: I just performed the OAuth 2 "dance" manually (using just my web browser and curl) and I was able to get a refresh token in the response. Here's what I did:

                In my browser, I entered the following into the address bar:

                Code:
                https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=MY_CLIENT_ID&access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&redirect_uri=MY_REDIRECT_URI
                (Be sure to substitute your app's values for MY_CLIENT_ID and MY_REDIRECT_URI.)

                After authorization, I get a callback to my redirect URI (there doesn't really need to be anything at that URI). In the address bar, I see the authorization code, so I copy it and use it in the following curl command line:

                Code:
                ~% curl -d "code=AUTHORIZATION_CODE&client_id=MY_CLIENT_ID&client_secret=MY_CLIENT_SECRET&redirect_uri=MY_REDIRECT_URI&grant_type=authorization_code" https://accounts.google.com/o/oauth2/token
                (Again, be sure to substitute your app's values and the authorization code for the all-caps values in that curl command line.)

                Upon submitting that, I got a JSON response that included the refresh token.

                I still do not know why it doesn't work for you with the changes you applied to the Google module, but maybe this will give you some clues.

                Comment


                • #9
                  Great, thanks! Yeah, I think there is some caching going on in the Google response, perhaps because their token is valid for an hour. I was thinking this yesterday already, but this confirms it.

                  Comment


                  • #10
                    Ok, I went through the oauth dance using curl etc. I simply don't get the refreshToken.

                    I get the keys: access_token,token_type,expires_in,id_token

                    I've reviewed the API console settings but I don't see anything relevant there. Since the offline access is a Web app specific type setting, I figured it might be something to do with this

                    Code:
                    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=MYCLIENTID.apps.googleusercontent.com&access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&redirect_uri=MYREDIRECT
                    
                    curl -k -d "code=MYCODEKEY&client_id=MYCLIENTID.apps.googleusercontent.com&client_secret=MYSECRET&redirect_uri=MYREDIRECT&grant_type=authorization_code" https://accounts.google.com/o/oauth2/token

                    Comment


                    • #11
                      Ok, resolved. You have to add the parameter

                      approval_type=force

                      to the parameters.

                      Comment


                      • #12
                        I believe that is only needed because the user has already granted permission to the app and so Google is just re-issuing the same response each time (without the refresh token, because it wasn't asked for the first time). You could've probably made it work by having the user revoke access to the app before trying to authorize again.

                        Having never authorized my sample app, I got it to work the first time, without approval_type=force. But again, that's just because I didn't already have a history of approval with Google.

                        Comment


                        • #13
                          By using Craig's suggestion to override GoogleOAuth2Template buildAuthorizeUrl I was able to get the refreshToken. I still have one minor problem. Once the refresh token is used, the refreshToken is changed to null by the framework; after calling connection.refresh(), the refreshToken value is wiped out and there is no way to manually update the Connection object with the old reusable refreshToken before calling connectionRepository.updateConnection(connection). I want to be able to update the connection in the userconnection table to retain the old refreshToken. Is there an easy way to populate the refreshToken field without having to write extra database code to do it? Preferably I would have liked to just call a public setter method on the Connection object.

                          Comment

                          Working...
                          X