Google: gapi authentication with oauth2 deprecation

1.4k views Asked by At

I want to authenticate gapi client library so I could create a spreadsheet on behalf of another user, i.e. oauth.

This code used to work:

gapi.load('client:auth2', function() {
gapi.auth2.init({
    clientId: 'CLIENT_ID',
      scope: 'https://www.googleapis.com/auth/spreadsheets',
    }).then(function() {
      return gapi.auth2.getAuthInstance().signIn();
    }).then(function() {
      console.log('Signed in!');
      
    }, function(error) {
      console.error(error);
    });
  });

Now however it is saying that gapi.auth2 is deprecated, so I try to do following

google.accounts.id.initialize({
    client_id: 'CLIENT_ID',
    callback: handleCredentialResponse
  });
  google.accounts.id.prompt();

  function handleCredentialResponse(response) {
     gapi.client.setToken(response.credential)
  }

And then

      function createSpreadsheet() {


        gapi.client.sheets.spreadsheets
          .create({
            properties: {
              title: "My New Spreadsheet",
            },
          })
          .then((response) => {
            // The spreadsheet is created successfully
            console.log("Spreadsheet created:", response.result.spreadsheetUrl);
          })
          .catch((err) => {
            console.error("Failed to create spreadsheet", err);
          });
      }

And this gives me "Missing credential error"

I've also tried setting credential like this: gapi.auth.setToken({ access_token: token }) Same error.

What am I missing?

1

There are 1 answers

0
Konstantin Rybakov On BEST ANSWER

After some time I've figured it out and was able to authenticate gapi to use spreadsheets API.

I was confused by ID token and Authorization token, those are 2 different things. Without further due, here's the working example:

var token;

function initGoogle() {
    // init client
    const client = google.accounts.oauth2.initTokenClient({
        client_id: "YOUR_CLIENT_ID",
        callback: handleCredentialResponse,

        scope: "https://www.googleapis.com/auth/spreadsheets",
    });
     
    // send authorize request
    // this prompts user to grant access
    client.requestAccessToken();
}

// this thing is needed to load spreadsheet client library JSON dicovery document
async function fetchDiscoveryDoc() {
    const resp = await fetch(
        "https://sheets.googleapis.com/$discovery/rest?version=v4"
    );
    return resp.json();
}


async function handleCredentialResponse(response) {

    console.log("loading client library");
    await new Promise((resolve) => {
        gapi.load("client", () => {
            resolve();
        });
    });

    const discoDoc = await fetchDiscoveryDoc();

    console.log("Loading spreadsheets");
    
    // loading spreadsheet library using discovery document
    await new Promise((resolve, reject) => {
        gapi.client.load(discoDoc).then(() => {
            console.log("Spreadsheets loaded");
            resolve();
        });
    });

    console.log("Setting authorization token");
    gapi.client.setToken(response);

    console.log("All set. Client is ready to make authorized API calls. Creating spreadsheet");

    await gapi.client.sheets.spreadsheets.create({
        properties: {
            title: "My New Spreadsheet",
        },
    });
}

Note, that this is implicit authorization flow, that is less secure, but does not involve backend. Read more here: https://developers.google.com/identity/oauth2/web/guides/use-token-model