I'm trying to build a google apps script that handles two spreadsheets concurrently - one contains private information for users; the other is public.
Because there's private information stored in it, I need to ensure that only the user has access to it. What I ultimately decided on (which may not be the best way to handle this) was to create a folder and file in the user's own google drive to store the data. I handle that inside my code.gs, and it works perfectly.
The problem comes when I try to access that data through my web app (which uses the same code.gs file). Even though users had to authorize my app to access their data when it first came up and tried to go make the file, the driveapp and spreadsheetapp authorizations don't seem to count for the web app. So, even though I have the fileId and url, I can't access it. I get the following error:
ACCESS_DENIED This spreadsheet is not publicly viewable and requires an OAuth credential
Am I correct in assuming that if I go in and build an OAuth credential using a clientID, that only works on MY spreadsheets, not my USER's spreadsheets? When I borrowed from Google's own page about spreadsheet authorization, https://developers.google.com/chart/interactive/docs/spreadsheets#Authorization, and built my app with only that (swapping in the urls and clientIDs as appropriate), I got this error:
- That’s an error.
Error: redirect_uri_mismatch
The JavaScript origin in the request, https://[gobblydygook1]-script.googleusercontent.com, does not match the ones authorized for the OAuth client. Visit https://console.developers.google.com/apis/credentials/oauthclient/[validClientID].apps.googleusercontent.com?project=901868773794 to update the authorized JavaScript origins.
Learn more Request Details
response_type=permission id_token scope=https://www.googleapis.com/auth/spreadsheets openid.realm= redirect_uri=storagerelay://https/[gobblydygook1]-script.googleusercontent.com?id=auth590482 client_id=[validClientID].apps.googleusercontent.com ss_domain=https://[gobblydygook1]-script.googleusercontent.com gsiwebsdk=shim
That’s all we know.
Unfortunately, I don't have my own domain... when I try to put in the actual website of my script, or the links that the error message provides to me, in the Credentials page, it doesn't seem to take them (or maybe it does and never shows them to me?).
All that said, I'm not even sure I'm doing this right in the first place, given that I'm trying to access a spreadsheet I created in my user's folder.
Can my code.gs somehow pass the authorization it used to get into that file over to the browser?
I could have code.gs go collect my data, but... doing so seems to be a few orders of magnitude slower than visualization queries.
Here's the code, in case you want to see it:
index.html:
<!DOCTYPE html>
<html>
<head>
<?var userSheetURL = getUserSheetUrl();?>
</head>
<body>
<h1>Hello, World!</h1>
<h3>User sheet URL is <?=userSheetURL?></h3>
<div id="user_sheet_url" data-url="<?=userSheetURL?>"></div>
<?!= include('demo'); ?>
<button id="authorize-button" style="visibility: hidden">Authorize</button>
<script src="https://apis.google.com/js/auth.js?onload=init"></script>
</body>
</html>
demo.html:
<link href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
var clientId = '[validClientId].apps.googleusercontent.com';
var scopes = 'https://www.googleapis.com/auth/spreadsheets';
function init() {
gapi.auth.authorize(
{client_id: clientId, scope: scopes, immediate: false},
handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick(event) {
gapi.auth.authorize(
{client_id: clientId, scope: scopes, immediate: false},
handleAuthResult);
return false;
}
function makeApiCall() {
var userUrl = $('#user_sheet_url').attr('data-url');
//the following alert is never triggered
alert(userUrl);
var tqUrl = userUrl + 'gviz/tq' +
'?tqx=responseHandler:handleTqResponse' +
'&access_token=' + encodeURIComponent(gapi.auth.getToken().access_token);
var slashScript = "/script"
document.write('<script src="' + tqUrl +'" type="text/javascript"><' + slashScript + '>');
}
function handleTqResponse(resp) {
document.write(JSON.stringify(resp));
}
</script>
(the call to getUserSheetUrl calls a function in code.gs that returns the url of the user's file I created. I can see that's returning successfully the string I want in the browser window)
I'm trying to access a spreadsheet I created in my user's folder.
, you want to access to a Spreadsheet in other user's Google Drive. Is my understanding correct? 2. Where are the scripts ofindex.html
anddemo.html
put? 3. What isgetUserSheetUrl()
? - TanaikeScriptApp.getOAuthToken()
. If I misunderstood your situation, I apologize. - Tanaike