Editor add-on authorization

Authorization for many Apps Script-based apps is straightforward because the script project asks for any missing permissions it needs when someone attempts to use it.

The authorization model for Editor add-ons is more complex for several reasons:

  • When a user creates a file, all the add-ons the user installs are listed in the Extensions menu, even if the user hasn't authorized those add-ons yet.

  • These add-ons work on files in Google Drive that can be shared with collaborators. Collaborators who don't have the Editor add-on installed see it in documents where the file creator used it.

  • Editor add-ons automatically run their onOpen() functions when a document opens.

To protect user data, authorization modes are applied that make some services unavailable to onOpen(). This guide can help you understand what your code can do and when.

Authorization model

The authorization mode of an Editor add-on depends on its state, which depends on who is using it: the user who installed the add-on or a collaborator.

Editor add-on states

Editor add-ons in the Extensions menu are installed, enabled, or both.

  • An add-on is installed for a particular user after they or their administrator get it from the Google Workspace Marketplace and authorize it to access their Google data.
  • An add-on is enabled in a document, form, presentation, or spreadsheet when anyone uses it there.
  • When people collaborate on a file and one of them uses an add-on, it's installed for the one user, and enabled for the file.

The following table summarizes the differences between installed and enabled. Note that when you test a script as an add-on you can run the test in either or both of these states.

Installed Enabled
Applies to User Document, form, presentation, or spreadsheet
Caused by Getting an add-on from the store Getting an add-on from the store while using that document, form, presentation, or spreadsheet, or
Using a previously installed add-on in that document, form, presentation, or spreadsheet
Menu visible to Only that user, in all documents, forms, presentations, or spreadsheets they open or create All collaborators on that document, form, presentation, or spreadsheet
Authorization mode for onOpen() AuthMode.NONE
(unless it's also enabled, in which case AuthMode.LIMITED)
AuthMode.LIMITED

Authorization modes

The onOpen() function of an Editor add-on runs automatically when a user opens a document, form, presentation, or spreadsheet. To protect users' data, Apps Script restricts what the onOpen() function can do. The Editor add-on state determines which authorization mode the onOpen() function runs in.

If an Editor add-on is enabled in the file, form, presentation, or spreadsheet, onOpen() runs in AuthMode.LIMITED. If the add-on isn't enabled and is only installed, onOpen() runs in AuthMode.NONE.

In AuthMode.NONE, an add-on can't run certain services until the user interacts with the add-on by clicking or running custom functions. If your add-on tries to use these services in onOpen(), onInstall(), or global scope, permissions fail and other calls, such as filling in menus, stop. Help is the only supported option.

To run restricted service calls, you must use the AuthMode.FULL authorization mode. User interaction functions, such as clicking a menu option, run only in this mode. After the code is run in AuthMode.FULL mode, the add-on can use all the scopes that the user authorized.

Apps Script passes the authorization mode as the authMode property of the Apps Script event parameter, e; the value of e.authMode corresponds to a constant in the Apps Script ScriptApp.AuthMode enum.

Authorization modes apply to all Apps Script execution methods, including running from the script editor, from a menu item, or from an Apps Script google.script.run call. However, the e.authMode property can only be inspected if the script runs as the result of a trigger such as onOpen(), onEdit() or onInstall(). Custom functions in Google Sheets use their own authorization mode, AuthMode.CUSTOM_FUNCTION, which is similar to LIMITED but has slightly different restrictions. For all other cases, scripts run in AuthMode.FULL, as described in the following table.

NONE LIMITED CUSTOM_FUNCTION FULL
Occurs for onOpen() (if the user has installed an add-on but not enabled it in the document, form, presentation, or spreadsheet) onOpen() (all other times)
onEdit() (only in Sheets)
Custom functions All other times, including:
installable triggers
onInstall()
google.script.run
Access to user data Locale only Locale only Locale only Yes
Access to document, form, presentation, or spreadsheet No Yes Yes — read-only Yes
Access to user interface Add menu items Add menu items No Yes
Access to Properties No Yes Yes Yes
Access to Jdbc, UrlFetch No No Yes Yes
Other services Logger
Utilities
Any services that don't access user data Any services that don't access user data All services

Authorization lifecycle of an Editor add-on

When an add-on is installed for the current user or enabled in the current file, the add-on is loaded for the document, form, presentation, or spreadsheet when that file is opened. The add-on is listed in the Extensions menu and starts listening for the simple triggers onInstall(), onOpen(), and onEdit(). If a user clicks an Extensions menu item, it runs.

The Editor add-on is installed

When an Editor add-on is installed from the store, its onInstall() function runs in AuthMode.FULL. In this authorization mode, the add-on can run a complex setup routine. You should also use onInstall() to create menu items, since the document, form, presentation, or spreadsheet is already open and your onOpen() function hasn't run. The following sample shows how to call the onOpen() function from the onInstall() function:

function onInstall(e) {
  onOpen(e);
  // Perform additional setup as needed.
}

The Editor add-on is opened

When a document, form, presentation, or spreadsheet opens, it loads every Editor add-on that the current user has installed or that any collaborator has enabled in the file, and calls each of their onOpen() functions. The authorization mode that onOpen() runs in depends on whether an add-on is installed or enabled.

If an add-on only creates a basic menu, the mode doesn't matter. The following sample shows a basic onOpen() function:

function onOpen(e) {
  SpreadsheetApp.getUi().createAddonMenu() // Or DocumentApp.
      .addItem('Insert chart', 'insertChart')
      .addItem('Update charts', 'updateCharts')
      .addToUi();
}

To add dynamic menu items based on stored Apps Script properties, to read the contents of the current file, or to perform other advanced tasks, you must identify the authorization mode and handle it appropriately.

The following sample shows an advanced onOpen() function that changes its action based on the authorization mode:

function onOpen(e) {
  var menu = SpreadsheetApp.getUi().createAddonMenu(); // Or DocumentApp.
  if (e && e.authMode == ScriptApp.AuthMode.NONE) {
    // Add a normal menu item (works in all authorization modes).
    menu.addItem('Start workflow', 'startWorkflow');
  } else {
    // Add a menu item based on properties (doesn't work in AuthMode.NONE).
    var properties = PropertiesService.getDocumentProperties();
    var workflowStarted = properties.getProperty('workflowStarted');
    if (workflowStarted) {
      menu.addItem('Check workflow status', 'checkWorkflow');
    } else {
      menu.addItem('Start workflow', 'startWorkflow');
    }
  }
  menu.addToUi();
}

Note that add-ons can't open sidebars or dialogs while executing in AuthMode.LIMITED. You can use menu items to open sidebars and dialogs since these run in AuthMode.FULL.

A user runs the Editor add-on

When a user clicks an Extensions menu item, Apps Script first checks whether the user has installed the add-on, and prompts them to do so if not. If the user has authorized the add-on, the script runs the function that corresponds to the menu item in AuthMode.FULL. The add-on is enabled in the document, form, presentation, or spreadsheet if it wasn't already.

Troubleshoot add-on menus not rendering

Your add-on menu might not render if your code doesn't manage the authorization modes correctly. For example:

  • An add-on tries to run an Apps Script service that isn't supported by the current authorization mode.

  • An add-on tries to run a service call before a user interacts with it.

To remove or rearrange a service call that's causing permission errors in AuthMode.NONE, try the following actions:

  1. Open the Apps Script project for your add-on and locate the onOpen() function.
  2. Search the onOpen() function for mentions of Apps Script services or objects associated with them, such as PropertiesService, SpreadsheetApp or GmailApp.
  3. If a service is used for anything other than creating the UI elements, remove it or wrap it in a comment block. Leave only these methods: .getUi(), .createMenu(), .addItem(), and .addToUi(). Also find and remove any service that is outside a function.
  4. Identify functions that could contain the lines of code commented or removed in the previous step, particularly those that use the information they produce, and move the service calls to the functions that need them. Rearrange or rewrite your codebase to accommodate the changes made in the previous steps.
  5. Save the code and create a test deployment.

    When you create a test deployment, make sure that the Config field is Installed for current user and that the text below the Config box says Test in AuthMode.None

  6. Launch the test deployment and open the Extensions menu.

  7. If all menu items are displayed, the problem is fixed. If you only see the Help menu, go back to step 1. You might have missed a service call.