31

How can I authenticate programmatically to Google? Now that ClientLogin (https://developers.google.com/accounts/docs/AuthForInstalledApps) is deprecated, how can we perform a programmatic authentication to Google with OAuth2?

With ClientLogin we could perform a post to https://www.google.com/accounts/ClientLogin with email and password parameters and obtain the authentication token.

With OAuth2 i can't find a solution!

#

My app is a java background process. I saw, following this link: developers.google.com/accounts/docs/OAuth2InstalledApp#refresh, how to obtain a new access token using a refreshed token.

The problem is that I can't find a java example about how to instantiate an Analytics object (for example) to perform a query when I have a new valid access token

This is my code that returns a 401 Invalid credentials when invoke the "execute()":

public class Test {

static final String client_id = "MY_CLIENT_ID";
static final String client_secret = "MY_SECRET";
static final String appName = "MY_APP";

private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();

static String access_token = "xxxx";
static String refreshToken = "yyyyy";

public static void main (String args[]){

    try {

        GoogleCredential credential = 
            new GoogleCredential.Builder()
                .setTransport(HTTP_TRANSPORT)
                .setJsonFactory(JSON_FACTORY)
                .setClientSecrets(client_id, client_secret).build();
        credential.setAccessToken(access_token);
        credential.setRefreshToken(refreshToken);
        //GoogleCredential
        Analytics analytics = Analytics.builder(HTTP_TRANSPORT, JSON_FACTORY)
            .setApplicationName(appName)
            .setHttpRequestInitializer(credential)
            .build();

        Accounts accounts = analytics.management().accounts().list().execute();
    } catch (Exception e) {
        e.printStackTrace();
    } 
}

What is the problem?

Matt C
  • 2,882
  • 3
  • 24
  • 17
Andrea Zonzin
  • 1,124
  • 2
  • 11
  • 26
  • 5
    could you please post your solution and how it's solved. I am facing same problem – RaceBase Sep 25 '13 at 04:16
  • can you please post the code of your solution. – Ninad Dec 12 '14 at 07:19
  • For those seeking a solution, I have posted one as an answer http://stackoverflow.com/a/34561285/752167 – Matt C Jan 03 '16 at 16:36
  • I've documented an example using Javascript and obtaining an Authorization Token here http://www.alexroque.com/?p=307 Hopefully it helps, What you want to do is make sure our return URI is setup correctly in your API console and that you parse the token correctly from the response. – AlexR Apr 29 '13 at 02:27

4 Answers4

16

Check the OAuth 2 flow for Installed Application:

https://developers.google.com/accounts/docs/OAuth2InstalledApp

It still requires the user to authenticate with a browser the first time, but then you can store the refresh token and use it for subsequent requests.

For alternative solutions, check the Device flow or Service Accounts, they are explained in the same documentation set.

Claudio Cherubino
  • 14,896
  • 1
  • 35
  • 42
  • 3
    I check the OAuth 2 flow for Installed Application but it soes not explain how to refresh the access token and how to perform an offline access (I need offline access for my bacgrond process). So I followed OAuth2 for Web Server Applications (here offline access is documented) but I have still problems. 1) I perform the first request via browser and I obtain autenticaton code for offline access 2) I perform a java post of the authentication code and obtain acces token and refresh token – Andrea Zonzin Jun 02 '12 at 17:47
  • 1
    Here is how you use a refresh token to obtain a new access token: https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh – Claudio Cherubino Jun 02 '12 at 17:48
  • I modify my question with code example to better explain my problem – Andrea Zonzin Jun 02 '12 at 18:21
  • 1
    Check the Google Drive Java tutorial for a complete sample showing how to address all edge cases in the OAuth flow: https://developers.google.com/drive/examples/java – Claudio Cherubino Jun 02 '12 at 18:26
  • 1
    The Google drive tutorial speaks about a webapp and a user session. I need an offline access to download data in a scheduled backgrond process. – Andrea Zonzin Jun 03 '12 at 09:20
  • Many thanks Claudio. With Google Drive tutorial I found answers for all my problems! Just a question: the tutorial uses classes com.google.api.services.oauth2.Oauth2 and com.google.api.services.oauth2.model.Userinfo to obtain user's info. In the last google-api-java-client these classes are not present. Do you know how can I obtain user info with new google-api-java-client? – Andrea Zonzin Jun 03 '12 at 19:40
  • 1
    The jar should be available here: http://code.google.com/p/google-api-java-client/wiki/APIs#oauth2 – Claudio Cherubino Jun 03 '12 at 19:55
  • 2
    $Andrea, if you found a solution, it would be helpful for others to see what it ended up being. Answer the question with what worked and accept it! – MuffinTheMan Apr 06 '13 at 22:01
  • @ClaudioCherubino I would be really greatful if you can help me with http://stackoverflow.com/questions/23010509/login-to-google-without-google-login-button-but-user-credentials For now I have figured out that I might as well go with your second solution. – Skynet Apr 11 '14 at 15:17
  • I added some further elaboration as an answer http://stackoverflow.com/a/34561285/752167 – Matt C Jan 02 '16 at 00:04
15

I found the Google Java client to be overly complex and poorly documented. Here's plain and simple Servlet example with Google Oauth2. For a background process you'll need to request access_type=offline. As others have mentioned you need the user to do a one time authorization. After that you can request refresh tokens as google tokens expire in an hour.

Andrew
  • 716
  • 1
  • 8
  • 19
  • Their documentation can certainly be frustrating and opaque, but the Java client for OAuth provided by Google does do a lot for you behind the scenes. Having said that, I agree it's overly-complex in implementation, and the example provided above is really helpful and nicely distills the OAuth flow in Java. Anyway, please see my answer showing how the Google client could be used http://stackoverflow.com/a/34561285/752167 – Matt C Jan 02 '16 at 00:14
  • Does the above example work? I tried I am getting No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:2828' is therefore not allowed access. The response had HTTP status code 405. @Andrew. Thanks for the help – therealprashant Apr 25 '18 at 10:48
12

Although I appreciate that the OP was originally targeting the OAuth2InstalledApp approach, I would like to point out a working solution using the OAuth2WebServer approach. They don't differ significantly and this worked for me. I have found the google OAuth library to be pretty good as it will handle most of the OAuth dance for you and it makes it easy to refresh the access token. The solution below depends on using a pre-obtained refresh token.

As the accepted answer states, to get OAuth authentication working (even for a Java background process) where the request relies upon access to user data

requires the user to authenticate with a browser the first time, but then you can store the refresh token and use it for subsequent requests.

From previous comments by the OP I see the following

So I followed OAuth2 for Web Server Applications (here offline access is documented) but I have still problems.
1) I perform the first request via browser and I obtain autenticaton code for offline access
2) I perform a java post of the authentication code and obtain acces token and refresh token

The approach I used is more like

1) I perform the first request via a browser and obtain the refresh token for offline access
2) In java I provide the refresh token to the library and the library will obtain the access token etc

specifically, using the google-api-java-client library the code is quite straightforward and note that I haven't set an access token as the OP did, as I am calling credential.refreshToken(); elsewhere. (I check if I have a valid access token already and if not call refresh prior to the API call)

  private Credential generateCredentialWithUserApprovedToken() throws IOException,
      GeneralSecurityException {
    JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    InputStreamReader inputStreamReader =
        new InputStreamReader(jsonFileResourceForClient.getInputStream());
    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(jsonFactory, inputStreamReader);
    return new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
        .setClientSecrets(clientSecrets).build().setRefreshToken(REFRESH_TOKEN);
  }

Note this covers step 2 of my approach, and the REFRESH_TOKEN mentioned in step 1 can be obtained as explained below.

First there is a prior set up of a web app creating an OAuth 2.0 client ID on the Google console for Credentials where you end up with a downloaded json file which will be read into the GoogleClientSecrets object.

i.e.

enter image description here

Make sure you add the Google playground callback uri into Authorized redirect URIs

enter image description here

Then you have your client id and the client secret ready for the playground and you can also download the json which you can pull into your Java code.

enter image description here

The REFRESH_TOKEN is obtained by sending a request to the google oauth playground with the following configuration. Note that prior to Step 1 and selecting your scope you should go to settings to check that you are providing you own credentials and add your client id and secret just below that

enter image description here

Note that the Access type is Offline, which corresponds to this.

There is also a nice explanation on grabbing the refresh token here https://www.youtube.com/watch?v=hfWe1gPCnzc

That is enough to get going and is a one time set up!

Regarding refresh tokens you should be aware of their lifecycle as discussed in the docs here

In the oauthplayground you will see this

enter image description here

but on point 4 of the docs here it says this

enter image description here

Hmmm.

Also for reference see How do I authorise an app (web or installed) without user intervention? (canonical ?)

Community
  • 1
  • 1
Matt C
  • 2,882
  • 3
  • 24
  • 17
  • I obtained the refresh token by doing the Java Quickstart, which opens a browser and prompts the user to login. Afterwards you can see the refresh token in the debugger for example. Seems to be a dirty hack, but well... it works. – Tim Büthe May 14 '16 at 20:09
  • You made my day. was searching for this from past two weekends. Don't forgot to add https://developers.google.com/oauthplayground in redirect uri instead of https://developers.google.com/oauthplayground/ (Slash in the last) – NameNotFoundException Dec 03 '16 at 18:26
  • What data type is "jsonFileResourceForClient" and what is it? – Taochok Oct 05 '17 at 11:30
  • I'll answer myself, the "jsonFileResourceForClient" is the client_secrets.json in an InputStreamReader. This worked for me: `new InputStreamReader(OAuth2TestV2.class.getResourceAsStream("/client_secrets.json"),"UTF-8")` instead of `new InputStreamReader(jsonFileResourceForClient.getInputStream());` – Taochok Oct 06 '17 at 11:41
0

For applications that authenticate on behalf of themselves (i.e., to another application, traditionally by signing into a role account using a shared password), the OAuth2 alternative to ClientLogin offered by Google is Service Accounts:

https://developers.google.com/accounts/docs/OAuth2ServiceAccount

breno
  • 3,226
  • 1
  • 22
  • 13