DEV Community

Enhancing Security in Apps Script

When building Google Apps Script projects, especially add-ons, gaining user trust is as crucial as the functionality you provide. A key part of building that trust is asking for only the permissions your script absolutely needs. This is where the @OnlyCurrentDoc annotation comes in, a simple but powerful feature for enhancing the security of your scripts.

The Problem with Broad Scopes

By default, Apps Script does a good job of determining the necessary OAuth scopes by scanning your code (Authorization Scopes). However, it can sometimes be overzealous, requesting broad scopes that grant access to all of a user's files of a certain type (e.g., all their Google Sheets).

For a user, seeing a prompt asking for permission to "View and manage all your Google Spreadsheets" can be alarming, especially if your add-on is only meant to work on the sheet they currently have open. This is where you can, and should, be more specific.

Introducing @OnlyCurrentDoc

The @OnlyCurrentDoc annotation is a piece of JSDoc that you add to a file-level comment in your script. It tells Apps Script to restrict its access to only the document, spreadsheet, or form that the script is currently bound to (Authorization for Google Services).

The official documentation explains it this way:

If you're building an add-on or other script that uses the Spreadsheet service, Document service, Slides service, or Forms service, you can force the authorization dialog to ask only for access to files in which the add-on or script is used, rather than all of a user's spreadsheets, documents, or forms. To do so, include the following JsDoc annotation in a file-level comment:

/** * @OnlyCurrentDoc */ 

By adding this simple comment, you change the authorization scope from a broad one to a much more specific and user-friendly one.

From Broad to Specific: The currentonly Scope

When you use @OnlyCurrentDoc, the OAuth scope requested by your script changes. For example:

  • https://www.googleapis.com/auth/spreadsheets becomes https://www.googleapis.com/auth/spreadsheets.currentonly
  • https://www.googleapis.com/auth/documents becomes https://www.googleapis.com/auth/documents.currentonly
  • https://www.googleapis.com/auth/presentations becomes https://www.googleapis.com/auth/presentations.currentonly

This tells the user that your script will only have access to the current file, which is a much more reassuring message.

Best Practice: Explicit Scopes in appsscript.json

While @OnlyCurrentDoc is a great start, the best practice for published applications is to explicitly define your scopes in the appsscript.json manifest file (Authorization Scopes). This gives you full control and makes your script's permissions crystal clear.

Here's an example of how you would declare the currentonly scope in your manifest:

{ "timeZone": "America/New_York", "dependencies": { }, "exceptionLogging": "STACKDRIVER", "runtimeVersion": "V8", "oauthScopes": [ "https://www.googleapis.com/auth/spreadsheets.currentonly", "https://www.googleapis.com/auth/script.container.ui" ] } 
Enter fullscreen mode Exit fullscreen mode

The Rare Exception: @NotOnlyCurrentDoc

In some rare cases, you might have a script that includes a library that uses @OnlyCurrentDoc, but your main script needs broader access. In this situation, you can use the @NotOnlyCurrentDoc annotation to override the library's restriction (Authorization for Google Services).

As the documentation states:

An opposing annotation, @NotOnlyCurrentDoc, is available if your script includes a library that declares @OnlyCurrentDoc, but the master script actually requires access to more than the current file.

Conclusion

Using @OnlyCurrentDoc and the corresponding ...currentonly scopes is a simple yet effective way to improve the security of your Apps Script projects and build trust with your users. It's a fundamental best practice for any script that works within a single document, and it's especially important for any add-on you intend to publish.


Additional Resources

Top comments (0)