spring-bootgoogle-drive-apijhipstergoogle-oauthgoogle-oauth-java-client

Google OAuth 2.0 server side access to Google Drive


I have created a user with access to a specific google drive. Through a Spring Boot application (jhipster) I connect with this user to the G-Drive. My problem is the authentication. I use this code in order to authenticate (as in the samples that Google provides for web applications):

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
    HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
    .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(".")))
    .setApprovalPrompt("auto")
    .build();
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

The first time the application starts it tries to find the StoredCredential file. If it does not then Google provides a link for the user to open it in his browser:

Please open the following address in your browser:
https://accounts.google.com/o/oauth2/auth?...

Since I am not able to do this from the EC2 instance I do this on my local computer and I upload the file on the expected location from the server. Finally a restart makes the web server to work for a while until the token expires. After that I have to do the same procedure.

Obviously I am doing something wrong here. What is the correct procedure for a web application to connect on the G-Drive every few minutes?

UPDATE: I found (https://cloud.google.com/storage/docs/authentication) that I must use a service account as the link suggests for the cloud storage. Unfortunately I have downloaded the json for the service account, set the env variable but this seems that it does not work for the google drive rest api (v3).

Thank you


Solution

  • thank you for the input but I finally found my answer. I used from the samples the code for the installed applications (Standalone applications).

    What I should have used instead is a "service account". This can be easily created from a normal Google user account. You will receive a JSON and you must set the full path to this json file in an environmental variable GOOGLE_APPLICATION_CREDENTIALS

    More information can be found here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount

    As soon as you have a GoogleCredential object the rest of the sample code remains the same.

    EDIT: The use of the solution that I described before "Installed Application"/"Standalone application" is ok for demonstration purposes where there is a user to actually press the link that will pop up and in order to refresh the expired token every 60 minutes or so.

    The correct solution is indeed to use a service account and impersonate the parent account (the one with who you created the service account). Here is a sample:

        GoogleCredential credential = new GoogleCredential.Builder()
            .setTransport(HTTP_TRANSPORT)
            .setJsonFactory(GCredentials.JSON_FACTORY)
            .setServiceAccountId("xxxxxx@xyz.iam.gserviceaccount.com")
            .setServiceAccountUser("This is the email of the real user that you want to impersonate")
            .setServiceAccountProjectId("The project ID")
            .setServiceAccountPrivateKeyFromP12File(p12File)
            .setServiceAccountScopes(SCOPES)
            .build();
    

    The administrator must give you the appropriate rights (SCOPES) as the ones that you declare and this must be done with the use of the CLIENT ID on the admin console.

    Also you must make sure that the account that you impersonate is a member of the g-drive folder. This is not required for the service account. The Project name must be correct as well when you create the DriveService instance. I hope this will help many people and avoid wasting a lot of time trying to connect successfully.