How to Validate Specific Users on a Web App in Google Apps Scripts

validate users to access a web app with Google Apps Script

You’ve created an awesome Google Apps Script web app for your secret society within your Google Workspace organisation or …dom! dom! DOM! … the world. The problem is that you only want to share your web app with the worthy. Those selected few. 🐐🛐🛐🛐

How do you do this? How to prevent this most coveted of apps from reaching the wrong hands?

It’s actually surprisingly simple.

In this tutorial, we will explore how to validate selected users to provide access to your web app. For our example, we validate users based on whether or not they have edit access to a Google Drive file ( a common occurrence). In the discussion, we will also look at alternative ways of validating emails.

One of the bonuses of the approach we will go through is that it can also be easily adapted for use in Google Workspace Add-ons, and Editor Add-ons like sidebars and dialogue boxes.

We’ll start off with an example and then move to a quick-use guide for those of you who just want to get in and apply the code to your own project. Then for those who want to know how it all works, I’ll dive into the details.

Let’s get started!

The Example

We’ll keep our example short and clean here. Let’s say we have shared a bunch of editors on a sacred secret document that we have called ‘Patters of the Goat’. It’s a detailed guide on displaying the best method, etiquette, and reverence when petting your favourite goat.

validated users in a webapp apps script share document
Click to Expand!

In our web app, we will have two HTML files. One for valid users who are edit members of the shared file that displays ‘You are worthy!’ The other for when the user is not valid and does not have edit membership to the file that displays ‘You are not worthy!’.

validated and invalidated HTML

We will deploy our web app to execute as ‘User accessing the web app’ and deploy to either ‘Anyone with Google Account’ or if you just want to run it in your Google Workspace organisation, ‘Anyone within Your Domain.

validated users in a webapp apps script deployment parameters
Click to Expand!

It doesn’t matter if a user had been given edit permissions with their individual email or as part of a group. Likewise, if a new editor is added or one is removed, this will be taken into account each time the user attempts to access the web app.

The Code

The code below contains a small example of how to apply it to run the HTML file ‘Index.html’ when the user is valid or ‘NonUser.html’ when the user should not have access to the web app. These file names can be updated and, of course, the contents of the HTML files adapted to your needs.

Go ahead and copy and paste these files into your own project and deploy them to try it out. Make sure you change the FILE_ID to your own file and share one or two people/accounts. Then test it out on an account that has no access or view/comment access and see what happens.

webApp.gs

Index.html

Hire me for our next Google Workspace project.

NonUser.html

 

Quick Use

If you haven’t yet created a web app project you can run the sample above and use the guide below if you get stuck:

https://yagisanatode.com/2020/11/11/google-apps-script-how-to-create-a-basic-interactive-interface-with-web-apps/

This tutorial can be quickly adapted to your own project by copying the validate() function into your code and then updating a few lines in your doGet() function that will initialise your web app.

Update the doGet() function

At the beginning of your doGet()function, add the following:

Line 3 will call the getActiveUser() method of the Google Apps Script Session class. We then call the getEmail() method to grab the active user. By active user, I mean the user who is running the script.

Line 4 is your file id to the file you have shared your editors on.

Line 6 then calls the validate() function taking the user email and file ID you gathered earlier as arguments. The validate() function returns true if the user is permitted to use the web app or false if they are not.

🐐You can support me for free by using this Amazon affiliate link in your next tech purchase :Computers & Stuff! 🐐

Finally, line 7 runs a ternary operator that checks if the isValid variable is true then it will assign the 'Index' to the htmlfile variable. Otherwise, it will assign the 'NonUser' file. You can, of course, update these file names to your own file names and modify the HTML files to fit your needs.

Adding the validate() function

Next, it is a simple case of adding the validate() function to your code.

Making some minor changes

You can make some quick changes to the validate() function to change from checking permissions a file to a folder and checking different types of permissions. Have a look at the three examples below.

Get list by editors of a folder instead of a file

In your doGet() function update your FileID variable to FolderID and replace it in the validate() second argument.

Within the emailList method inside validate(), change the getFileById() method of the DriveApp class with getFolderById().

You could also find and replace all the instances where it says ‘file’ with ‘folder’ if you want to tidy things up too.

Get users with ‘view’ access to file instead of editors

Here we can alter the validate() function again so that we only allow users to our web app who have ‘view’ access. Back in the email list method, change the .getEditors() method with .getViewers().

 

Get all users who have access to a file

If any user does not have any type of access to the file then when the DriveApp.getFileById() method is called it will report an error. This means that if we want to give access to our web app to anyone who can access the file, then we can simply use the first part of the emailList method exclusively.

 

IF you are keen to learn more about how the validate() function works. Read on, ya big legend!

Create and Publish a Google Workspace Add-on with Apps Script Course

Need help with Google Workspace development?

Go something to solve bigger than Chat GPT?

I can help you with all of your Google Workspace development needs, from custom app development to integrations and security. I have a proven track record of success in helping businesses of all sizes get the most out of Google Workspace.

Schedule a free consultation today to discuss your needs and get started or learn more about our services here.


The video

Code Breakdown

In this section, we will take a quick look at the validate function.

The validate() function is set up as, I guess, a pseudo-class or closure with two private methods emailList() and groupEmailList(). This is just to keep things a little contained so we don’t have to worry as much about any naming conflicts with your own project.

Set user validity

First, we set user validity with our isValid variable. This is first set to false indicating that the user does not have access. This variable will be updated if the code finds that the user has access.

emailList()

The emailList variable contains either the list of editors in the list or group emails with edit permissions. We will wrap it all up in an Immediately Invoked Function Expression (IIFE) so that it is all nice and ready. Notice the extra outer bracket in the arrow function that finished with an empty bracket to create our IIFE – (function)().

First, we create the file variable to store our file constructor data that we will get from the DriveApp Google Apps Script Class (line 8). We will use a Javascript try…catch statement to catch the instance when the user has no access to the file. We attempt to call the getFileById() method from the DriveApp class using our fileID as the argument.

If we are successful, then this will store the constructor data for the selected file that we can extract our emails from in a minute. If we are not successful (catch), we will return false.

Lines 16-18, we use the file constructor to return the getEditors() method. This will provide us with an array of all the editor’s information for the file. Now we can use the Javascript map() method to iterate through this array calling the getEmail() sub-method for each editor.

Once outside of the emailList variable we check if it is false. If so, we update the isValid variable to false and return it to indicate that the user does not have access to the file.

However, we can’t simply stop here. It is often good practice for organisations to manage their permissions by groups. This means an owner of a document might be giving edit permissions to a group email rather than an individual’s email. The getEditors() method will only grab the email addresses assigned to the document or folder, whether they be a group email address or an individual one. We will need to check the users in a group in our next task.

an alternative approach (…ish)

You can also check the file permissions of a user by using the getAccess() method. Something like this:

While a little shorter and ostensibly faster, this approach suffers from the same problem that it does not check a user who is a part of a group with edit permissions (The user’s file access will result in ‘NONE’). Plus it doesn’t give us a convenient list of editor emails that we can use in a moment to check if the current active user is a member of an editor group.

groupEmailList()

For our groupEmailList variable we need to check if our emailList variable contains any groups, and if they do, check each group to see if our current active user is a member.

On line 8, we first create an isMemberOfGroup variable and set it to false. Later, if we do find the currently active user is a member of a group in the emailList, this variable will be updated to true.

We can now use the Google Apps Script GroupsApp class to get all the groups the active user is a member of. To do this we call the getGroups() method which will return an array of all the groups as objects. From this, we can use the JavaScript map() method to create an array or each group’s email address with getEmail(). Lines 10-11

Next, we can iterate through each one of these group emails with the JavaScript forEach() method. On each iteration, we can check the emailList to see if it contains one of the active user’s groups with JS includes(). If the includes method finds a match, then we update and return isMemberOfGroup to true.

Checking if the active user is an editor

Finally, we check the emailList for a match of the active user’s email with JS includes(). If they exist, then we update isValid to true. Otherwise, we check to see if the groupEmailList returned true. If it did, we set isValid to true.

Create and Publish Google Workspace Add-ons with Apps Script Course 300px

Lastly, we return the isValid results back to the doGet() web app initialisation function so it can be used to determine which HTML file to present to the user.

Discussion

The benefit of setting a validator before the HtmlService is initialised is that there is not awkward back and forth between Apps Script and web app front end once the file is loaded. Validation is done as soon as the user opens the web app, making it a pretty secure approach.

This approach also opens itself up to alternate validation methods. Here are a couple of other variation approaches you could consider:

  • A list of emails in a Google Sheet.
  • A separate server with stored emails with Google Apps Script’s UrlFetchApp.
  • From your script PropertiesService. This could be updated or cross-checked against a separate file regularly using a time trigger.

Likewise, you might want to create different web-app displays depending on the user’s task requirement. For example, imagine you have a slightly different web app for editors, commenters and viewers of a document.

So do you think you would use this approach in your own web app, sidebar or dialogue box? How would you modify it or improve on it? I always love to hear how people apply their knowledge to projects and your ideas could inspire the next reader.

If you like the tutorial, please consider a donation to keep the site running or shout me a coffee to keep me going. You can find links to PayPal or cryptocurrencies on my Cointree page here. You can even send me a message, for you know… the warm and fuzzies.

~Yagi 🐐

10 thoughts on “How to Validate Specific Users on a Web App in Google Apps Scripts”

  1. Hi Yagi

    I developed a similar code but with a different purpose, (a web app deployed to “execute as me”).

    My problem is that Session.getActiveUser (). GetEmail () returns a blank string because the user running it belongs to a different domain. I need another method to identify the user who loads the application, would you give me a recommendation on how to identify a user from another domain?

    Thank you

    1. Hi Carlos,

      When “execute as me” you are pretty stuck for options, beyond really getting involved and using Google Identity services which is a beefy topic. Or using something like Firebase Authentication.
      Can I ask if there is a reason why you chose to “execute as me”? If you need to save data to say a private Google Sheet, you could alternatively save user inputs in Properties Service – Script Properties. And then run a time trigger to regularly update the sheet.

      ~Yagi

      1. Thanks Yagi, you gained a subscriber for your Youtube channel for the recommendation to use Properties Service. Effectively “execute as me” to be able to write to a private sheet

        1. You’re welcome Carlos. Glad I could help.

  2. my get email function is not working too. something google changed and did not announced yet

    1. Hi Asif,

      Google is pretty good at supporting legacy code and processes and will give ample warning when they are grandfathered. Having said that, no complicated piece of software is without its bugs.

      More often than not the bugs come from us 😄.

      Can you share your error? What line is it occurring on? Is this in relation to the Session.getActiveUser().getEmail(), file or group getEmail() methods?
      How is our webapp being deployed? You will need to deploy as:

      • Execute as: User accessing the web
      • Who as access: Anyone who has a google account OR users on your domain

      ~Yagi

  3. Hi Yagi

    How can we use this code with a custom login screen?

    Or we have an option to go back to the google login screen. Say for example, once a user tries to login using the google login screen and if he is restricted then, on the restriction page, he should have the option to go back to the login screen and try with another credential.

    Thanks,
    Soheb

    1. Hi Soheb,

      If a user is not logged into their Google Account then they will get a request to log in. Your best bet then is that if they are denied access with our code, then you could add a link in the denied HTML file to say that they should try and log in with another account.

      Unfortunately, you can’t force logging out of accounts with Google, that would cause some pretty serious security issues I would imagine.

      Hope this helps.

      ~ Yagi.

  4. hi Yagi, thank you for your work as usual 🙂 I’asking you a hint if possible. I want to deal with a similar scenario, but I have deployed a web app that will be accessed through an http request (via UrlFetchApp). it seems to me that a similar web app will work only with the option “execute as me”. in this scenario, opening a file whose editors/viewers are the authorized ones will ever work, since the user that is opening the file is ‘me’ and not the user running the script. have you any suggestion to set things in this case? thank you in advance

    1. Hi Dani,

      Have a look at the Session class and test out the difference between effective and active users this might be a solution for you.

      ~ Yagi

Leave a Reply