Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using "USER_PASS" with datastudio connector

I am having a bit of trouble setting up the "USER_PASS" type of authentication for my datastudio connector, and have had a hard time finding adequate examples (the official documentation offers but a partial picture). Has anyone set this up before, and could you please share with me how you had to configure it? If anyone has a link to an example that would be a great help, thanks!

like image 343
Logan Murphy Avatar asked Jan 01 '23 15:01

Logan Murphy


1 Answers

Oh how I know and share the pain of finding adequate examples.. The kaggle connector mentioned by @diminishedprime actually is using what I found to be working, too. Here is an abridged example which I hope is helpful for you.


Basically you will need a combination of things. The first would be to implement getAuthType() to tell the Data Studio that it might need to display such a mask:

function getAuthType() {      
  return {
    type: 'USER_PASS'
  };
};

Then, because you are using USER_PASS, the Data Studio invokes isAuthValid() and expects it to return a Boolean. Everytime you are on the first page of the configuration for the data source that uses your connector, this function is invoked. If it returns false, a mask like this will be displayed:

Authenticate using <code>USER_PASS</code>

But if it returns true, this step will be jumped over.

But what is the logic behind that, you might ask? I myself and the kaggle connector are using the UserProperties to persist the username/password with which to use this data source. You can check if the right credentials are there and authenticate them via your REST endpoint and return your Boolean according to this. It might look something like this:

function isAuthValid() {
  const usernameAndPassword = loadUsernameAndPassword();
  return usernameAndPassword.username && usernameAndPassword.password && validateCredentials(usernameAndPassword.username, usernameAndPassword.password)
};

loadCurrentUsernameAndPassword() just loads them from the UserProperties:

function loadCurrentUsernameAndPassword() {
  const properties = PropertiesService.getUserProperties();
  return {
    username: properties.getProperty('dscc.username'),
    password: properties.getProperty('dscc.password')
  }
};

validateCredentials() is explained further down.


When the user types his username/password and clicks the Send-Button (I assume that's what it's called in english), the Data Studio then invokes setCredentials(), which you will need to implement. You would probably need to call your REST endpoint, send the username/password and process the reply. It may look something like this:

function setCredentials(request) {
  var isCredentialsValid = validateCredentials(request.userPass.username, request.userPass.password);
  if (!isCredentialsValid) {
    return {
      errorCode: "INVALID_CREDENTIALS"
    };
  } else {
    storeUsernameAndPassword(request.userPass.username, request.userPass.password);
    return {
      errorCode: "NONE"
    };
  }
};

As you can see, I have introduced 2 new functions.

The first new function validateCredentials() actually sends the credentials to the REST endpoint, using UrlFetchApp:

function validateCredentials(username, password) {
  var rawResponse = UrlFetchApp.fetch('path/to/your/authentication/endpoint', {
    method: 'GET',
    headers: {
      'Authorization': 'Basic ' + Utilities.base64Encode(username + ':' + password)
    },
    muteHttpExceptions: true
  });

  return rawResponse.getResponseCode() === 200;
}

The second new function storeUsernameAndPassword() stores the username/passwort into the UserProperties:

function storeUsernameAndPassword(username, password) {
  PropertiesService
    .getUserProperties()
    .setProperty('dscc.username', username)
    .setProperty('dscc.password', password);
};

Now you have a valid username and password stored in the UserProperties which you can send to your REST endpoint whenever the Data Studio invokes getData(). For instance like this:

function getData(request) {
  const usernameAndPassword = loadUsernameAndPassword();

  var rawResponse = UrlFetchApp.fetch('path/to/your/data/endpoint?foo=bar', {
    method: 'GET',
    headers: {
      'Authorization': 'Basic ' + Utilities.base64Encode(usernameAndPassword.username + ':' + usernameAndPassword.password)
    }
  });

  // transform your rawResponse ...
}

Now, there is an issue with this approach, which can't be resolved right now. The UserProperties will not be cleared ever. So in theory, without hacking around, the username/password combination, once typed and validated by the user and stored into the UserProperties, are there forever. According to the Community Connector API Reference, we can implement resetAuth() where this information could be removed from the UserProperties, but it seems resetAuth() is currently never being invoked, ever. I already started a discussion about that issue here.


It is also somewhat explained at https://developers.google.com/datastudio/connector/auth

like image 153
Gregor Sondermeier Avatar answered Jan 14 '23 18:01

Gregor Sondermeier