Authorization Scopes in Google Apps Script: Convenience vs. Security
Tags: gas, googleappsscript, security
Published: 2023-12-17 14:16:05

Authorization scopes are a crucial element of any Apps Script, as they determine what your script is allowed to do. More importantly, they set the boundaries for the script, providing security (more on that [here](https://dataful.tech/apps-script/scopes/how-to-manage-and-audit/)). That is why it is vital to understand how to properly set the required scopes and which scopes to use.

## How to set scopes in Apps Script

There are two ways to identify the permission scopes required for a script: automatically and manually (explicitly).

### Setting Scopes Automatically

In automatic mode, when you run the script, Google checks if the script uses functions that require specific permissions, such as `UrlFetchApp`, `SpreadsheetApp` (often they end with "App"). If it does, Google will ask you for the permissions required to work with those functions. This is very convenient for the developer, yet it does compromise security.

In the example above, Google will ask you to grant the script two permissions: full access to all your spreadsheets (`SpreadsheetApp`) and access to external services (`UrlFetchApp`):

![App asking for full access to all your spreadsheets](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pi413if9dux3zd3rcaj3.png)

Access to external services is acceptable -- there is no other way to achieve the same result, and on its own, it is difficult to misuse. However, full access to all spreadsheets is too broad. In most cases, you want to write data to the sheet the script is attached to. Thus, you only need access there, which would be much safer. There is a special permission for that which needs to be set manually.

### Setting Scopes Manually (Explicitly)

The best security practice is to request as narrow permissions as possible, which would still be enough to do the job. In this case, if anything goes wrong (whether it's a bug in the code or a security breach), the scope of the problem will be limited. To do this with Google Apps Script, you need to identify the required permissions explicitly.

Every Apps Script project has an `appscript.json` manifest file, which is hidden by default (I guess this is to promote bad security practices). To make it accessible, you need to open the project's settings and enable `Show "appsscript.json" manifest file in editor`:


![Enable access to appsscript.json manifest file in the project settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2sr4u6xgyhpql7oxj5e.png)

After that, the manifest file will appear in the list of files and will always be at the top. By default, it will contain only basic details of the project:

![Default appsscirpt.json manifest file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csxsbowvv6lspuicbbtw.png) 

To set the proper authorization scopes, you need to add the `oauthScopes` property with the values. Following the example above, to require permission to access external services and the spreadsheet the script is attached to, the file should look as follows:

```json
{
  "timeZone": "America/Toronto",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets.currentonly",
    "https://www.googleapis.com/auth/script.external_request"
  ]
}
```

> **Important:** If you set permissions explicitly, you must provide an exhaustive list of permissions the script needs. Otherwise, performing an action that you do not have permission for will cause an error.

## What Scopes to Use

There are three types of authorization scopes: regular, sensitive (containing user data like email, name, etc.), and restricted ([examples](https://support.google.com/cloud/answer/9110914#restricted-scopes)). Depending on your use case, you might need to go through a special authorization process to use sensitive or restricted scopes. If you have fewer than 100 users of a given script, you usually do not have to do this, but you will be subject to the unverified app screen.

You can find a list of most of the scopes for many Google services [here](https://developers.google.com/identity/protocols/oauth2/scopes).

Let's look at the most commonly used scopes:

- **Access only to the document the script is attached to** -- a must-have and the easiest way to make your sheets safer. These scopes are so safe that on their own, they do not require a security warning (and with this trick you can [work with the data from other sheets](https://dataful.tech/apps-script/security/how-to-store-secrets/#two-documents-attached-script-and-importrange) without more extensive permissions):
  - Sheets: `https://www.googleapis.com/auth/spreadsheets.currentonly`
  - Docs: `https://www.googleapis.com/auth/documents.currentonly`
  - Slides: `https://www.googleapis.com/auth/presentations.currentonly`
- **Read-only scopes.** These are the next best choice if you need to read data from documents other than the one where the script is installed.
  - Sheets: `https://www.googleapis.com/auth/spreadsheets.readonly`
  - Docs: `https://www.googleapis.com/auth/documents.readonly`
  - Slides: `https://www.googleapis.com/auth/presentations.readonly`
  - Drive: `https://www.googleapis.com/auth/drive.readonly`
- **Complete access to all documents of a given type.** These are some of the most dangerous scopes possible and are highly discouraged unless absolutely necessary. Even then, use them with security precautions.
  - Sheets: `https://www.googleapis.com/auth/spreadsheets`
  - Docs: `https://www.googleapis.com/auth/documents`
  - Slides: `https://www.googleapis.com/auth/presentations`
  - Drive: `https://www.googleapis.com/auth/drive`
- **Making requests to external services** via `UrlFetchApp`: `https://www.googleapis.com/auth/script.external_request`
- **Getting the email of the user** running the script via `Session.getActiveUser().getEmail()`: `https://www.googleapis.com/auth/userinfo.email`
- **Accessing the user interface (UI):** `https://www.googleapis.com/auth/script.container.ui`. This is mostly for complex UI interactions when creating custom interfaces. It does not include simple alerts and custom menus -- you can do those without this permission.
- **Creating and deleting triggers, working with user's permissions via ScriptApp:** `https://www.googleapis.com/auth/script.scriptapp`. Use this scope with caution, as it allows the creation of triggers, and triggers can run the script in your name without your knowledge. You can manage existing triggers here.

---

We have reviewed two ways to set permission scopes.  **The main takeaways:**
1. Always set scopes explicitly, without relying on auto-detection which is often too permissive.  It takes a minute to set up in the very beginning but makes our lives easier and safer later.
2. Use as narrow scopes as possible. 
3. Bonus point: learn [how to audit scopes you have already granted](https://dataful.tech/apps-script/scopes/how-to-manage-and-audit/).