Search code examples
google-oauthaccess-tokendriverefresh-tokengoogle-api-js-client

Getting refresh token and exchanging for access token Google Drive Javascript API?


I am using the Google Drive API as well as the Google Picker API on the frontend. My goal is to get users to authorize their drive account to be used, and subsequently be able to call the Google Picker API whenever they want without re-authorizing their drive.

// Authorizing client initially (I only want them to have to do this once)
await gapi.load("client:auth2", async () => {
  clientInit = window.gapi.auth2.init({
    client_id: driveClientId,
    scope: driveScope,
  });
  await gapi.client.load('drive', 'v2', () => { handleAuthResult(clientInit) });
});

// Setting the access token (expires in 3600s)
async handleAuthResult(authResult) {
    let signInResponse = await authResult.signIn();
    let googleOAuthToken = signInResponse.wc["access_token"];
}

// Creating picker
 new google.picker.PickerBuilder()
    .addView(docsView)
    .setOAuthToken(googleOAuthToken)
    .setCallback(drivePickerCallback)
    .build();

The picker has the .setOAuthToken(access_token) method that takes the access_token as a parameter. The one that you originally get after authorizing the drive expires in 1 hour, and its not giving me a refresh token to get another access token with. signInResponse.wc does not contain a refresh token.

I am confused as to how to get this refresh token, and then how to use it to get an access token, the documentation is not quite clear.


Solution

  • Okay, so I was able to solve this using the .grantOfflineAccess() method. This returns an authorization code that can be used to exchange for a refresh token by making a POST request to https://www.googleapis.com/oauth2/v4/token.

    // Getting refresh token 
    
    let offlineAccess = await signInResponse.grantOfflineAccess();
    
    // Authorization code can be used to exchange for a refresh token
    let refreshAccessCode = offlineAccess.code;  
    let tokenRequest = await axios.request({
        method: 'post',
        url: "https://www.googleapis.com/oauth2/v4/token",
        headers: {"content-type": "application/x-www-form-urlencoded"},
        params: {
          code: refreshAccessCode,
          client_id: this.driveClientId,
          client_secret: this.driveClientSecret,
          redirect_uri: "postmessage",
          grant_type: "authorization_code"
        }
     });
    
    let googleOAuthToken = tokenRequest.data["refresh_token"];
    

    Now that you have the refresh token, you can exchange it for an access token by making another POST request as follows:

    // Exchanging refresh token for access code
    
    let tokenRequest = await axios.request({
        method: 'post',
        url: "https://oauth2.googleapis.com/token",
        headers: {"content-type": "application/x-www-form-urlencoded"},
        params: {
          client_id: driveClientId,
          client_secret: driveClientSecret,
          refresh_token: googleOAuthToken,
          grant_type: "refresh_token"
        } 
     });
      
    let accessToken = tokenRequest.data["access_token"];