Integrating Google Drive infrastructure in Play Scala application


This blog talks about integrating the Google Drive infrastructure in Play Scala application as like Assembla and some others. We used oauth2 in order to communicate with the Google using Access Token and Refresh Token. Let us see the process step by step.

1. Prepare the browser request URL in order to get the authorization code.

val redirectURI = "http://localhost:9000/driveAuth"

  def authenticateToGoogle = Action { implicit request =>
    val urlToRedirect = new GoogleBrowserClientRequestUrl("Client ID", redirectURI, Arrays.asList("https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/drive")).set("access_type", "offline").set("response_type", "code").build()
    Redirect(urlToRedirect)
  }

Parameters required by this URL :

ClientId : Your Google application’s client Id. Looks like xxxxxxxxxxxx.apps.googleusercontent.com
Redirect URI : The registered URI with the application.
Scopes : : Specific information type that you want to demand from user.
Access Type : Should be set as “offline”.
Response Type : Should be set as “code” as we are demanding the authorization code. This code will be exchanged for the access token and the one time refresh token.

2. When the users will hit this url , they’ll be asked to Log in and allowing the application to access of their Google Drive’s documents and the other basic information (Depends upon the scope that we’ve defined in url). Once the users have successfully authenticated their Google accounts , the authorization code will be sent to the Redirect URI specified in the browser’s request url as request’s query parameter.

3. Once you receive the authorization code over the redirect uri that you’ve specified as like above , use this code for getting the Access Token and one time Refresh Token from Google by making a POST request on https://accounts.google.com/o/oauth2/token url. Again you’ve to send the basic credentials like Client_Id , Client_Secret , Redirect_URI etc along with this request.


import com.google.api.client.googleapis.auth.oauth2.GoogleCredential
import com.google.api.client.http.FileContent
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.jackson.JacksonFactory
import com.google.api.services.drive.Drive
import com.google.api.services.drive.model.File

......................................................
......................................................

 /**
   * Google Oauth2 accessing code and exchanging it for Access & Refresh Token
   */
  def googleDriveAuthentication = Action { implicit request =>
    val code = request.queryString("code").toList(0)
    val url = "https://accounts.google.com/o/oauth2/token"
    val obj = new URL(url)
    val con = obj.openConnection().asInstanceOf[HttpsURLConnection]

    con.setRequestMethod("POST");
    con.setRequestProperty("User-Agent", USER_AGENT);
    con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");

    val urlParameters = "code=" + code + "&client_id=************.apps.googleusercontent.com&client_secret=xxxxxxxxxx&redirect_uri=http://localhost:9000/driveAuth&grant_type=authorization_code&Content-Type=application/x-www-form-urlencoded";
    con.setDoOutput(true)
    val wr = new DataOutputStream(con.getOutputStream)
    wr.writeBytes(urlParameters)
    wr.flush
    wr.close
    val in = new BufferedReader(
      new InputStreamReader(con.getInputStream))
    val response = new StringBuffer

    while (in.readLine != null) {
      response.append(in.readLine)
    }
    in.close
    Ok
}

You’ll get the following data in response.

"access_token" : "ya29.AHES6ZSyNMy0btyYrYflOPkYGEF6ijCKjCASjYoxK5CuqHPOHLDG0og",  "expires_in" : 3600,  "refresh_token" : "1/U33p2VTgqIqtll2P43x6PVen156ys0EMGcrkYW4lYuMI"

5. Extract out the access token and the refresh token from the response.

Refresh token will be obtained only first time when the user will allow the access to their information. Don’t forget to save it in to your database. Next time when you’ll generate access token using this refresh token.

6. Now we are having access token so its time to set the Google credentials in order to make the Drive ready.

 val CLIENT_ID = "************.apps.googleusercontent.com"
  val CLIENT_SECRET = "****************"
  val httpTransport = new NetHttpTransport
  val jsonFactory = new JacksonFactory
  /**
   * Set Up Google App Credentials
   */
  def prepareGoogleDrive(accessToken: String): Drive = {

    //Build the Google credentials and make the Drive ready to interact
    val credential = new GoogleCredential.Builder()
      .setJsonFactory(jsonFactory)
      .setTransport(httpTransport)
      .setClientSecrets(CLIENT_ID, CLIENT_SECRET)
      .build();
    credential.setAccessToken(accessToken);
    //Create a new authorized API client
    new Drive.Builder(httpTransport, jsonFactory, credential).build()
  }

7. Now our Drive is ready. We can now upload the documents or fetch all the documents of a user’s Google drive and more depending upon the scope defined. Below is how you’ve to upload a file to Google drive and viewing the already existing files of a user.

/**
   * Upload To Google Drive
   */
  def uploadToGoogleDrive(accessToken: String, fileToUpload: java.io.File, fileName: String, contentType: String): String = {
    val service = prepareGoogleDrive(accessToken)
    //Insert a file
    val body = new File
    body.setTitle(fileName)
    body.setDescription(fileName)
    body.setMimeType(contentType)
    val fileContent: java.io.File = fileToUpload
    val mediaContent = new FileContent(contentType, fileContent)
    //Inserting the files
    val file = service.files.insert(body, mediaContent).execute()
    file.getId

  }
  /**
   * Get All Files From Google Drive
   */

  def getAllDocumentsFromGoogleDocs(code: String): List[(String, String)] = {
    val service = prepareGoogleDrive(code)
    var result: List[File] = Nil
    val request = service.files.list

    do {
      val files = request.execute
      result ++= (files.getItems)
      request.setPageToken(files.getNextPageToken)
    } while (request.getPageToken() != null && request.getPageToken().length() > 0)

    result map {
      case a => (a.getOriginalFilename, a.getAlternateLink)
    }
  }

8. Next time when the user will Log in to the system , you’d having refresh token already of the Google account of that particular user. You can use this refresh token in order to generate the new access token for the communication with user’s Google drive. Here is how you can generate the new access token from the previously existing refresh token.

/**
   * Get Access token Using refresh Token
   */

  def getNewAccessToken(refreshToken: String):String = {
    val credentialBuilder = new GoogleCredential.Builder()
      .setTransport(httpTransport).setJsonFactory(jsonFactory)
      .setClientSecrets(CLIENT_ID, CLIENT_SECRET);

    val credential = credentialBuilder.build()
    credential.setRefreshToken(refreshToken)
    credential.refreshToken()
    credential.getAccessToken
  }

This is the pretty straightforward way of how you can communicate with the Google Drive. Thank you folks !

About Neelkanth Sachdeva

Software Consultant @ Knoldus Software LLP Co-Founder @ My Cell Was Stolen
This entry was posted in Scala, Web and tagged , , , . Bookmark the permalink.

3 Responses to Integrating Google Drive infrastructure in Play Scala application

  1. baronseiya says:

    You can use Scala Dispatch http://dispatch.databinder.net/Dispatch.html
    And transform this:

    val obj = new URL(tokenURI)
    val con = obj.openConnection().asInstanceOf[HttpsURLConnection]

    Logger.info(code)

    con.setRequestMethod("POST");

    val urlParameters = s"code=${code}&client_id=${clientId}&client_secret=${clientSecret}&redirect_uri=${redirectURI}&grant_type=authorization_code&Content-Type=application/x-www-form-urlencoded";
    Logger.info(urlParameters)

    con.setDoOutput(true)
    val wr = new DataOutputStream(con.getOutputStream)
    wr.writeBytes(urlParameters)
    wr.flush
    wr.close
    val in = new BufferedReader(new InputStreamReader(con.getInputStream))
    val response = new StringBuffer

    while (in.readLine != null) {
    response.append(in.readLine)
    }
    in.close
    Logger.info(response.toString)

    Into this:


    val tokenRequest = url(tokenURI) < code, "client_id" -> clientId, "client_secret" -> clientSecret, "redirect_uri" -> redirectURI, "grant_type" -> "authorization_code", "Content-Type" -> "application/x-www-form-urlencoded")
    val tokenJson = Http(tokenRequest OK as.String)
    tokenJson.map(Logger.info(_))

    Also, in the first line, you can define the scopes like this:

    val scopes = "https://www.googleapis.com/auth/youtube.readonly" :: Nil

    and use scopes.asJava

    Anyway, thanks for your post! :)

  2. Pingback: Create, Upload & Delete Google Docs using Play Scala application | Knoldus

  3. Pingback: Integrating Google Drive in Play Scala application with Google+ | Knoldus

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s