google-drive-apigoogle-api-js-clientgoogle-identitygoogle-drive-picker

Drive file picker from the older Google Sign-In platform library to the newer Google Identity Services library for authentication


I have a code where I read the file data as blob. I have implemented using the old gapi, how do I migrate from the older Google Sign-In platform library to the newer Google Identity Services library for authentication.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <title>Google Picker Example</title>
    
  </head>
  <body>
    <button id="authorize_button" style="display: none;">Authorize</button>
    <button id="signout_button" style="display: none;">Sign Out</button>
    <div id="result"></div>

    <script type="text/javascript" src="script.js"></script>
    <script async defer src="https://apis.google.com/js/api.js"
    onload="this.onload=function(){};handleClientLoad()"
    onreadystatechange="if (this.readyState === 'complete') this.onload()">
  </script>
  
  <script>
const API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const CLIENT_ID = '995979103146-6qdmadbu7ha5ptrthsg8uqonkpplvc8e.apps.googleusercontent.com';
const appId = "995979103146";

const SCOPES = ["https://www.googleapis.com/auth/drive"];

const DISCOVERY_DOCS = [
  "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest",
];

const authorizeButton = document.getElementById("authorize_button");
const signoutButton = document.getElementById("signout_button");

// Use the Google API Loader script to load the google.picker script.
function handleClientLoad() {
  gapi.load("client:auth2:picker", initClient);
}

function initClient() {
  gapi.client.init({
      apiKey: API_KEY,
      clientId: CLIENT_ID,
      discoveryDocs: DISCOVERY_DOCS,
      scope: SCOPES[0]
    })
    .then(
      function () {
        // Listen for sign-in state changes.
        gapi.auth2.getAuthInstance().isSignedIn.listen(handleSignIn);

        // Handle the initial sign-in state.
        handleSignIn(gapi.auth2.getAuthInstance().isSignedIn.get());
        authorizeButton.onclick = handleAuthClick;
        signoutButton.onclick = handleSignoutClick;
      },
      function (error) {
        appendPre(JSON.stringify(error, null, 2));
      }
    );
}

function handleSignIn(isSignedIn) {
  if (isSignedIn) {
    authorizeButton.style.display = "none";
    signoutButton.style.display = "block";
    createPicker();
  } else {
    authorizeButton.style.display = "block";
    signoutButton.style.display = "none";
  }
}

function handleAuthClick(event) {
  gapi.auth2.getAuthInstance().signIn();
}

function handleSignoutClick(event) {
  gapi.auth2.getAuthInstance().signOut();
}

function createPicker() {
  const token = gapi.client.getToken().access_token
  if (token) {
    
    let view = new google.picker.View(google.picker.ViewId.DOCS);
    view.setMimeTypes("image/png,image/jpeg,image/jpg");
    let picker = new google.picker.PickerBuilder()
      .enableFeature(google.picker.Feature.NAV_HIDDEN)
      .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
      .setAppId(appId)
      .setOAuthToken(token)
      .addView(view)
      .addView(new google.picker.DocsUploadView())
      .setDeveloperKey(API_KEY)
      .setCallback(getFile)
      .build();
    picker.setVisible(true);
  }
}

function getFile(pickerResp) {
    console.log(JSON.stringify(pickerResp))
    if(pickerResp.action == "picked") {
  gapi.client.drive.files
    .get({
      fileId: pickerResp.docs[0].id,
      alt: 'media'
    })
    .then(resp => {
      console.log("fetch response", resp.status)
      let binary = resp.body
      // EDIT - addition from Gabrielle vvvv
      let l = binary.length
      let array = new Uint8Array(l);
      for (var i = 0; i<l; i++){
        array[i] = binary.charCodeAt(i);
      }
      let blob = new Blob([array], {type: 'application/octet-stream'});
      console.log(blob)
      // EDIT - addition from Gabrielle ^^^^
});
}
}
  </script>
  
  </body>
</html>

     


Solution

  • It is really easy to implement the new Google Identity Library. As you can compare here, you only have to change a few things.

    This example is the easiest approach (implicit flow):

    1. One button for retrieving the token
    2. One button for loading the picker
    <html>
      <body>
        <script
          src="https://accounts.google.com/gsi/client"
          onload="initClient()"
          async
          defer
        ></script>
    
        <script>
          var client;
          var access_token;
          
          function loadPicker() {
          gapi.load('picker', {'callback': ()=>console.log("Picker Loaded")});
        }
          function initClient() {
            client = google.accounts.oauth2.initTokenClient({
              client_id: "<CLIENT_ID>",
              scope:
                "https://www.googleapis.com/auth/drive.file",
              callback: (tokenResponse) => {
                access_token = tokenResponse.access_token;
              },
            });
          }
          function getToken() {
            client.requestAccessToken();
          }
          function revokeToken() {
            google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
          }
          function onPickerApiLoad() {
            var picker = new google.picker.PickerBuilder()
              .addView(google.picker.ViewId.DOCS)
              .setOAuthToken(access_token)
              .build();
            picker.setVisible(true);
          }
        </script>
    
        <!-- The Google API Loader script. -->
        <h1>Google Identity Services Authorization Token model</h1>
        <button onclick="getToken();">Get access token</button><br /><br />
        <button onclick="onPickerApiLoad()">Load picker</button>
        <script src="https://apis.google.com/js/api.js?onload=loadPicker"></script>
      </body>
    </html>
    
    Documentation: