Skip to content
// Apps Script

Fix "Authorization is required to perform that action" in Apps Script.

Why Apps Script throws "Authorization is required to perform that action" after adding a new service, and the two reliable ways to fix it: re-running from the editor or pinning explicit OAuth scopes in appsscript.json.

I added a new Google service to my existing Apps Script project and now every run fails with "Authorization is required to perform that action" even though I already granted permissions before.

The script

copy · paste · trigger
Code.gs
Apps Script
// appsscript.json oauthScopes (Project Settings > Show manifest)
// Pin these so the consent screen re-triggers on deploy, not just editor runs.
// "oauthScopes": [
//   "https://www.googleapis.com/auth/spreadsheets",
//   "https://www.googleapis.com/auth/gmail.send"
// ]

function sendSheetSummary() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var lastRow = sheet.getLastRow();
  var range = sheet.getRange(1, 1, lastRow, 2).getValues();
  var body = range.map(function(row) { return row[0] + ': ' + row[1]; }).join('\n');
  GmailApp.sendEmail('[email protected]', 'Sheet summary', body);
  Logger.log('Sent ' + lastRow + ' rows');
}

Need a variant? Gnaw writes a custom version from one sentence — fields, triggers, edge cases handled.

Walkthrough

Why the error appears after you add a new service

Apps Script builds an OAuth scope set from every Google service your code references. When you first authorized the project, it asked for exactly those scopes. The moment you add a call to a new service — say, GmailApp after your script previously only touched SpreadsheetApp — the required scope set changes, but the stored authorization token does not. The runtime hits a Gmail API call, checks the token's granted scopes, finds gmail.send missing, and throws the error.

The frustrating part: the error message says nothing about which scope is missing. It reads the same whether you forgot one scope or ten. If your script calls multiple services, you may trip over this error again after each addition until you resolve the full set.

Quickest fix: re-run any function from the script editor

Open the Apps Script editor, pick any function in the dropdown at the top, and click Run. Because you are authenticated as a human in a browser session, Apps Script can detect the scope mismatch, cancel the run, and immediately show the Google consent screen listing the new permissions it needs. Accept, and the stored token is replaced with one covering the updated scope set.

This works every time for scripts you run manually. The first time I hit this on a scheduled trigger, I wasted twenty minutes tailing logs before I realized triggers run as the script owner's stored token — they cannot pop a consent screen. The editor run is the only interactive path to re-authorization.

Triggers and add-on deployments share the same limitation. If your script runs on a time-based trigger and you changed scopes, you must do one manual editor run to refresh the token before the trigger will succeed again.

Permanent fix: pin oauthScopes in the manifest

By default, Apps Script infers scopes automatically, which means the scope set silently expands whenever you add a service call. Pinning explicit scopes in appsscript.json opts you out of inference and makes the authorization state predictable.

Enable the manifest file via Project Settings > Show 'appsscript.json' manifest file in editor. Add an oauthScopes array listing every scope your script needs. From that point on, Apps Script uses exactly those scopes — no more, no fewer. If you add a new service later and forget to add its scope to the manifest, the script will error and the manifest is the first place you look.

The practical benefit for deployed add-ons and triggers is that the scope set is visible in version control and code review. Implicit inference hides scope creep; explicit scopes surface it. For production scripts I always pin scopes and treat an unexpected re-auth prompt as a signal that something changed in the code.

Want a custom version?

Describe your sheet and the rule you want. Gnaw writes the Apps Script — fields, triggers, edge cases — in one shot.

FAQ

4 questions
I ran the script from the editor and accepted permissions, but the error still appears on my time-based trigger.
Triggers use the token that was stored at the last authorization. Run any function from the editor once after re-authorizing, confirm it succeeds, then let the trigger fire. If the error persists, open Executions in the left sidebar and check whether the trigger is running as a different user — shared scripts run as the file owner, not the trigger creator.
How do I find out which specific scope is missing?
Apps Script does not name the missing scope in the error message. The fastest method: open the OAuth consent screen flow by running from the editor and read the permissions list it presents. Alternatively, check the Apps Script dashboard under Project Settings > Scopes — this shows the inferred set Apps Script calculated from your current code.
Does revoking app access from myaccount.google.com fix this?
Revocation forces re-authorization from scratch, which does trigger the consent screen on the next editor run. It works, but it is heavier than necessary. Revoking and re-granting changes nothing about the underlying scope mismatch — the root fix is either running from the editor to accept new scopes, or pinning oauthScopes in the manifest.
My script uses ScriptApp.getOAuthToken() and I need the new scope available at runtime. Do I need anything extra?
Yes. ScriptApp.getOAuthToken() returns the token scopes that were granted at authorization time. If gmail.send was not in the scope set when the user last authorized, the returned token will not include it regardless of what your code calls. You must re-authorize (editor run or manifest pin plus re-deploy) before the token carries the new scope.
// one good script a week

Get a working Apps Script snippet in your inbox, weekly.