0

Currently attempting to execute a GAS from a Javascript client. The GAS script is as follows:

function findAndReplace() {
    var doc = DocumentApp.openById('ID_OMITTED');
}

This executes fine by pressing Play in the GAS editor, however when I try to execute from my Javascript client, I click authorise.

Authorisation

Then I receive a 401.

Error calling API: {
    "error": {
        "code": 401,
        "message": "ScriptError",
        "status": "UNAUTHENTICATED",
        "details": [{
            "@type": "type.googleapis.com/google.apps.script.v1.ExecutionError",
            "errorMessage": "Authorization is required to perform that action.",
            "errorType": "ScriptError"
        }]
    }
}

And now when I press Play in the GAS editor, I get a Action not allowed error. I can then create a new script by copying it, press Play and it works fine. Executing the from the Javascript causes the whole the 401 and then the whole cycle repeats.

However if I execute a simple:

function test() {
    return 'hello';
}

It works, and returns

Folders under your root folder:
    h (0)
    e (1)
    l (2)
    l (3)
    o (4)

(The output looks like this because the program expects an array, as you can see below).

This is the Javascript client, basically copy and paste of the Javascript quickstart.

var CLIENT_ID = 'CLIENT_ID_OMITTED';
var SCOPES = ['https://www.googleapis.com/auth/drive'];

function checkAuth() {
    gapi.auth.authorize(
        {
            'client_id': CLIENT_ID,
            'scope': SCOPES.join(' '),
            'immediate': true
        }, handleAuthResult
    );
}

function handleAuthResult(authResult) {
    var authorizeDiv = document.getElementById('authorize-div');
    if (authResult && !authResult.error) {
        authorizeDiv.style.display = 'none';
        callScriptFunction();
    } else {
        authorizeDiv.style.display = 'inline';
    }
}

function handleAuthClick(event) {
    gapi.auth.authorize(
        {client_id: CLIENT_ID, scope: SCOPES, immediate: false},
        handleAuthResult
    );
    return false;
}

function callScriptFunction() {
    var scriptId = "SCRIPT_ID_OMITTED";

    var request = {
        'function': 'findAndReplace'
    };

    var op = gapi.client.request({
        'root': 'https://script.googleapis.com',
        'path': 'v1/scripts/' + scriptId + ':run',
        'method': 'POST',
        'body': request
    });

    op.execute(function(resp) {
        if (resp.error && resp.error.status) {
            appendPre('Error calling API:');
            appendPre(JSON.stringify(resp, null, 2));
        } else if (resp.error) {
            var error = resp.error.details[0];
            appendPre('Script error message: ' + error.errorMessage);

            if (error.scriptStackTraceElements) {
                appendPre('Script error stacktrace:');
                for (var i = 0; i < error.scriptStackTraceElements.length; i++)         {
                    var trace = error.scriptStackTraceElements[i];
                    appendPre('\t' + trace.function + ':' + trace.lineNumber);
                }
            }
        } else {
            var folderSet = resp.response.result;
            if (Object.keys(folderSet).length === 0) {
                appendPre('No folders returned!');
            } else {
                appendPre('Folders under your root folder:');
                Object.keys(folderSet).forEach(function(id){
                    appendPre('\t' + folderSet[id] + ' (' + id  + ')');
                });
            }
        }
    });
}

function appendPre(message) {
    var pre = document.getElementById('output');
    var textContent = document.createTextNode(message + '\n');
    pre.appendChild(textContent);
}    

I made sure to create the permissions for DocumentApp, by copying it. Which when the copy is ran it gives me this prompt:

Permission request

Which I obviously accept.

I create a new project on the script each time, enabling the Scripts API

Enabling API

and then creating an OAuth2 client,

Creating client id

copying the client id into the script. I also Deploy as API Executable on the script, and take the script id.

What am I missing? Why is the code producing a 401? And why is the GAS script then mysteriously returning Action now allowed in the editor only to work once its copied?

Thanks in advance.

Jack
  • 804
  • 7
  • 18

1 Answers1

0

After trying to do this for a couple nights I solved it straight after posted to SO... typical!

This post solved it

Basically, go to File > Project Properties and click the Scopes tab. From here you can see all the scopes required by your project.

This then must be added to the scopes array in your client-side javascript.

So my scopes now looks like this:

var SCOPES = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/documents'];

Why the GAS script then decide to return Action not allowed I'll never know, it really threw me off the trail.

Hopefully this helps some body else.

Community
  • 1
  • 1
Jack
  • 804
  • 7
  • 18