Search code examples
google-apps-scriptweb-applicationsoauthservice-accountsgoogle-workspace

Is it possible to access a deployed Protected Google Web App via URL without logging in from browser each time?


I've deployed a protected web app, and I'd like to trigger it without logging in each time: enter image description here

I'd like to access the web app URL without logging in: enter image description here

Based on this document, it's not possible without logging in from browser: https://github.com/tanaikech/taking-advantage-of-Web-Apps-with-google-apps-script/blob/master/README.md

If the script of Web Apps uses some scopes, client users have to authorize the scopes by own browser.

I'm assuming scopes means the web app is protected.

I've tried this: https://github.com/gsuitedevs/apps-script-oauth2/blob/master/samples/GoogleServiceAccount.gs but it asks for "request access"

https://i.imgur.com/eRUaXlh.png

If I click on request access, then it shows me this: enter image description here

At this point, I'm thinking it's not possible to setup a service account with scope to trigger a protected deployed web app without authenticating through a browser each time. Can anyone confirm this?

My assumption is that the web app scope is https://www.googleapis.com/auth/drive since it has access to all drive's files.

Update: (What I tried but didn't work)

I matched the scope from the script:

enter image description here

To the service account:

enter image description here

The blurred area above is the client id i got from:

enter image description here

I've generated the access token using this script:

function accessTokens(){
 var private_key = "-----BEGIN PRIVATE KEY-----*****\n-----END PRIVATE KEY-----\n"; // private_key of JSON file retrieved by creating Service Account
var client_email = "****@****.iam.gserviceaccount.com"; // client_email of JSON file retrieved by creating Service Account
var scopes = ["https://www.googleapis.com/auth/documents","https://www.googleapis.com/auth/forms","https://www.googleapis.com/auth/script.external_request","https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email"]; // Scopes


var url = "https://www.googleapis.com/oauth2/v3/token";
var header = {
  alg: "RS256",
  typ: "JWT",
};
var now = Math.floor(Date.now() / 1000);
var claim = {
  iss: client_email,
  scope: scopes.join(" "),
  aud: url,
  exp: (now + 3600).toString(),
  iat: now.toString(),
};
var signature = Utilities.base64Encode(JSON.stringify(header)) + "." + Utilities.base64Encode(JSON.stringify(claim));
var jwt = signature + "." + Utilities.base64Encode(Utilities.computeRsaSha256Signature(signature, private_key));

var params = {
  method: "post",
  payload: {
    assertion: jwt,
    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
  },
};
var res = UrlFetchApp.fetch(url, params).getContentText();
Logger.log(res); 
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getSheetByName("Sheet1");
  sheet.getRange(1, 3).setValue(JSON.parse(res)['access_token']);
}

And still has the same error, it asks for request access.


Solution

  • After a couple days into this, I've figured it out (with help of course).

    1. Get the scope from your deployed web app script: File > Project Properties > Scopes
    2. Add the scope along with https://www.googleapis.com/auth/drive in page Manage API client access https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients (use comma delimited to add multiple scopes: http...,http..., etc.)
    3. For the client name, get the client id from the service account page in your admin console: https://console.developers.google.com
    4. Deploy your script Publish > Deploy as Web App
    5. After generating access token(instruction below), append the access token with your deployed web app url &access_token=YOURTOKENHERE

    Use this script with a google sheet, it will generate the access_token in cell A1 of Sheet1 (Replace the 4 variables with the info relevant to you):

    function accessTokens(){
     var private_key = "-----BEGIN PRIVATE KEY-----n-----END PRIVATE KEY-----\n"; // private_key of JSON file retrieved by creating Service Account
    var client_email = "*****@****.iam.gserviceaccount.com"; // client_email of JSON file retrieved by creating Service Account
    var scopes = ["https://www.googleapis.com/auth/documents","https://www.googleapis.com/auth/forms","https://www.googleapis.com/auth/script.external_request","https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/drive"]; // Scopes
    var impersonate_email = "" //impersonate email
    
    var url = "https://www.googleapis.com/oauth2/v4/token";
    var header = {
      alg: "RS256",
      typ: "JWT",
    };
    var now = Math.floor(Date.now() / 1000);
    var claim = {
      iss: client_email,
      sub: impersonate_email,
      scope: scopes.join(" "),
      aud: url,
      exp: (now + 3600).toString(),
      iat: now.toString(),
    };
    var signature = Utilities.base64Encode(JSON.stringify(header)) + "." + Utilities.base64Encode(JSON.stringify(claim));
    var jwt = signature + "." + Utilities.base64Encode(Utilities.computeRsaSha256Signature(signature, private_key));
    
    var params = {
      method: "post",
      payload: {
        assertion: jwt,
        grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
      },
    };
    var res = UrlFetchApp.fetch(url, params).getContentText();
    Logger.log(res); 
        var ss = SpreadsheetApp.getActiveSpreadsheet();
        var sheet = ss.getSheetByName("Sheet1");
      sheet.getRange(1, 1).setValue(JSON.parse(res)['access_token']);
    }