authorizationUrl on sidebar of gmail addons using appscript - google-apps-script

I am using Google cloud datastore which is exposed by jersey rest, i have made authentication using oauth2 to access rest APIS.
Now I want to call restful API from my gmail addons to populate some lovs on gmail sidebar.
I have tried oauth2 authentication provided on https://github.com/googlesamples/apps-script-oauth2.
How do i show authorizationUrl on sidebar of gmail using gmail Addons?
CODEBASE
appscript.json
{
"timeZone": "America/Los_Angeles",
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "Gmail",
"serviceId": "gmail",
"version": "v1"
}],
"libraries": [{
"userSymbol": "OAuth2",
"libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF",
"version": "24",
"developmentMode": true
}]
},
"oauthScopes": ["https://www.googleapis.com/auth/gmail.addons.execute", "https://www.googleapis.com/auth/gmail.addons.current.message.metadata", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/script.storage"],
"gmail": {
"name": "Gmail Add-on Quickstart",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/2x/bookmark_black_24dp.png",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "buildAddOn"
}],
"primaryColor": "#4285F4",
"secondaryColor": "#4285F4",
"openLinkUrlPrefixes": ["https://mail.google.com/"],
"version": "TRUSTED_TESTER_V2"
}
}
Code.gs
function buildAddOn(e) {
var driveService = createOauthService();
Logger.log('Access'+driveService.hasAccess()); // GETTING FALSE HERE
Logger.log('Auth URL'+driveService.getAuthorizationUrl()); // GETTING PROPER AUTH URL.
Logger.log('Token'+driveService.getAccessToken()); // NEED TOKEN TO BE USED ON REST CALL
}
function createOauthService() {
return OAuth2.createService('drive')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId('MY CLOUD CONSOLE CLIENT ID')
.setClientSecret('MY SECREAT')
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('https://www.googleapis.com/auth/drive')
.setParam('login_hint', Session.getActiveUser().getEmail())
.setParam('access_type', 'offline');
.setParam('approval_prompt', 'force');
}
Is this correct way or am i missing something ?
Please suggest.

One documented way to do this is to return a card from your buildAddOn() function which contains a button configured to launch the authorization sequence.
function buildAuthorizeCard() {
var authorizationUrl = getOAuthService().getAuthorizationUrl();
var card = CardService.newCardBuilder();
var section = CardService.newCardSection();
section.addWidget(CardService.newTextButton()
.setText("Authorize MyService")
.setAuthorizationAction(
CardService.newAuthorizationAction()
.setAuthorizationUrl(authorizationUrl)
));
card.addSection(section);
return card.build();
}
You can give that a try.

Related

Google Workspace Add-on for Calendar Conference Solution with OAuth2 integration fails on redirect with CORS

I have built a google workspace addon for calendar conference solution using app script and oauth2 library.
My oauth client code is:
return (
OAuth2.createService("OAuthApp")
// Set the endpoint URLs.
.setAuthorizationBaseUrl(`${FRONTEND_DOMAIN}/auth/login`) // frontend api
.setTokenUrl(`${BACKEND_DOMAIN}/v1.0/oauth/exchange-code-for-token`) // backend api
// Set the client ID and secret.
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
// Set the name of the callback function that should be invoked to
// complete the OAuth flow.
.setCallbackFunction("authCallback")
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
.setCache(CacheService.getUserCache())
.setLock(LockService.getUserLock())
);
Where for setAuthorizationBaseUrl i have provided out frontend page to open login page for user to authenticate. When user authenticates successfully, backend redirects to the addon on https://script.google.com/macros/d/{SCRIPT_ID}/usercallback with auth code in params and status code 302.
However when i redirect the frontend to addon from backend i get this error in console:
Access to XMLHttpRequest at 'https://script.google.com/macros/d/{SCRIPT_ID}/usercallback?code=4611729c041e9d0f93506bcfa772707d' (redirected from 'https://{BACKEND_ENDPOINT}/oauth/verify-otp') from origin 'https://{FRONTEND_ENDPOINT}' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
My add on manifest is:
{
"oauthScopes": [
"https://www.googleapis.com/auth/calendar.addons.execute",
"https://www.googleapis.com/auth/calendar.events.readonly",
"https://www.googleapis.com/auth/calendar.addons.current.event.read",
"https://www.googleapis.com/auth/calendar.addons.current.event.write",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.scriptapp"
],
"addOns": {
"common": {
"homepageTrigger": {
"enabled": false
},
"logoUrl": "https://lh3.googleusercontent.com/-WuPhRsFGKUc/XCng7m_FIxI/AAAAAAAAAGg/ASH4GCGDMs0d55OZQGCSIQHXjRAKnkeTQCLcBGAs/s400/jitsi-logo-96x96.png",
"name": "Conference App"
},
"calendar": {
"conferenceSolution": [
{
"id": 1,
"name": "Private Meeting",
"logoUrl": "https://lh3.googleusercontent.com/-WuPhRsFGKUc/XCng7m_FIxI/AAAAAAAAAGg/ASH4GCGDMs0d55OZQGCSIQHXjRAKnkeTQCLcBGAs/s400/jitsi-logo-96x96.png",
"onCreateFunction": "createPrivateMeeting"
}
],
"currentEventAccess": "READ_WRITE"
}
},
"timeZone": "America/New_York",
"runtimeVersion": "V8",
"dependencies": {
"enabledAdvancedServices": [
{
"userSymbol": "Calendar",
"serviceId": "calendar",
"version": "v3"
}
],
"libraries": [
{
"userSymbol": "OAuth2",
"version": "43",
"libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF"
}
]
},
"webapp": {
"access": "ANYONE",
"executeAs": "USER_ACCESSING"
},
"exceptionLogging": "STACKDRIVER"
}
From the network it seems the browser makes a preflight request when redirected from the backend to the google script and fails with cors error.
I tried to change the Content-Type in headers to text/plain;charset=utf-8 to avoid the preflight request but the cors issue still persists.
I am expecting the popup to get redirect to addon and exchange the auth code for auth token.
The mistake i was making was redirecting the popup to appscript from backend. Instead of returning the redirect uri with auth code concatenated in response from the backend to the popup/frontend and frontend redirects which fixes the cors mismatch error.

Google Apps Scripts no longer runs getActiveUser() during on-sheet script triggers [duplicate]

This question already has answers here:
Custom function throws a "You do not have the permission required to setValue" error
(4 answers)
Custom function permissions [duplicate]
(2 answers)
Google Apps Scripts no longer runs getActiveUser() within Sheets custom button triggers
Closed 8 months ago.
This post was edited and submitted for review 8 months ago and failed to reopen the post:
Needs details or clarity Add details and clarify the problem by editing this post.
The following functions used to work but no longer work unless the scripts are ran inside the console. Session.getActiveUser() would usually run inside Google Sheets scripts assigned to an inserted drawing or a time based trigger. When the scripts are ran, Session.getActiveUser() only runs if I (the spreadsheet owner) run the scrip. If it's someone else, it either doesn't work or Session.getActiveUser().getEmail() outputs a blank string. To be clear, all scripts are ran within a spreadsheet environment. NOT a deployed web app.
function printEmail()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Test Stuff");
var outputCell = ss.getRangeByName("testOutput");
Logger.log(Session.getActiveUser().getEmail());
outputCell.setValue( Session.getActiveUser().getEmail());
}
function printAdminEmail()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Test Stuff");
var outputCell = ss.getRangeByName("testOutput");
outputCell.setValue( Session.getEffectiveUser().getEmail());
}
Here is a screenshot of attempting to run the script from a spreadsheet drawing. Returns blank. Drawing assigned to "printEmail"
Here is the JSON Manifest.
{
"timeZone": "America/New_York",
"dependencies": {
"enabledAdvancedServices": [
{
"userSymbol": "Sheets",
"version": "v4",
"serviceId": "sheets"
},
{
"userSymbol": "DocsList",
"version": "v1",
"serviceId": "docs"
},
{
"userSymbol": "Calendar",
"version": "v3",
"serviceId": "calendar"
},
{
"userSymbol": "People",
"version": "v1",
"serviceId": "peopleapi"
},
{
"userSymbol": "Tasks",
"version": "v1",
"serviceId": "tasks"
}
]
},
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.readonly",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/contacts.readonly",
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.google.com/m8/feeds",
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.google.com/calendar/feeds",
"https://www.googleapis.com/auth/documents",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.modify",
"https://mail.google.com/",
"https://www.googleapis.com/auth/gmail.addons.current.action.compose",
"https://www.googleapis.com/auth/tasks"
],
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"sheets": {
"macros": [
{
"menuName": "sortCaseload",
"functionName": "sortCaseload"
},
{
"menuName": "df",
"functionName": "df"
}
]
},
"webapp": {
"executeAs": "USER_ACCESSING",
"access": "DOMAIN"
}
}

NewUpdateDraftActionResponseBuilder crashes the Gmail IOS app

On the current Gmail iPhone app, calling the newUpdateDraftActionResponseBuilder crashes the app. No errors get logged and those crashed calls never appear in the 'Executions' tab in the App Script console.
The same code runs fine on the Android Gmail app or in the browser.
Code to reproduce
index.gs
function attachRecording() {
return CardService.newUpdateDraftActionResponseBuilder()
.setUpdateDraftBodyAction(CardService.newUpdateDraftBodyAction()
.addUpdateContent('<h1>hello</h1>', CardService.ContentType.IMMUTABLE_HTML)
.setUpdateType(CardService.UpdateDraftBodyType.IN_PLACE_INSERT))
.build();
}
appsscript.json
{
"timeZone": "America/New_York",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.addons.current.action.compose",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/gmail.addons.execute"
],
"addOns": {
"common": {
"name": "Vocal",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/mic_black_48dp.png",
"universalActions": [
{
"label": "Manage account",
"openLink": "https://app.vocal.email"
}
],
"homepageTrigger": {
"runFunction": "onWelcomeClick"
},
"openLinkUrlPrefixes": [
"*"
]
},
"gmail": {
"composeTrigger": {
"selectActions": [
{
"text": "Record voice message",
"runFunction": "attachRecording"
}
],
"draftAccess": "NONE"
}
}
}
}
I tried the different methods of the function listed here: https://developers.google.com/apps-script/reference/card-service/update-draft-action-response-builder
Whether it's adding a subject or text/html in the body. it always crashes the app.

Google Apps Script event object is undefined in my Gmail add-on

The problem is that my function receives an undefined event object. Can you tell me what's the problem?
Here's the function:
function onGmailMessageOpen(event) {
const { accessToken, messageId } = event.commonEventObject;
return buildCard();
}
Here's the appsscript.json manifest:
{
"timeZone": "Europe/Kiev",
"dependencies": {
"enabledAdvancedServices": [
{
"userSymbol": "Gmail",
"version": "v1",
"serviceId": "gmail"
}
]
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://mail.google.com/",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.addons.current.message.readonly",
"https://www.googleapis.com/auth/gmail.addons.current.message.metadata",
"https://www.googleapis.com/auth/gmail.metadata"
],
"gmail": {
"name": "Contacts",
"logoUrl": "https://lh4.googleusercontent.com/dfdvUXkVaB8yVTsrnuFagTy9YDvEPz3jqJWhFNpxKbbJhq7kdOTkwfoSEtn4VBOb9tZ_B6DT3Q-L4wU5Cw-FCcYY4fISn29OkcBOCwp69q5GxI4AM2WXHHk6kaQtgA",
"contextualTriggers": [
{
"unconditional": {},
"onTriggerFunction": "onGmailMessageOpen"
}
],
"primaryColor": "#547dbf"
},
"runtimeVersion": "V8",
"webapp": {
"executeAs": "USER_ACCESSING",
"access": "ANYONE"
}
}
The function declaration function onGmailMessageOpen(event) {/**/} tells that your function is designed to receive a properly populated event object.
Do not run the code directly in the script editor. If you do, theĀ event object will not be properly populated, causing the error you mention.
What you should do is let Google's code call the function when the user opens a message in the UI. When called like this, the event object will be properly populated.

BigQuery - Google Sheets error when try to refresh data connection using macro

Trying to refresh BigQuery data connection (Google Sheets) using Macro, but it failed. It showed this error:
BigQuery error: Error while reading table: worker-information.worker_details.xxxx_global_worker_malaysia, error message: Failed to read the spreadsheet. Errors: No OAuth token with Google Drive scope was found.
Here is the macro script:
function refresh2() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A1').activate();
SpreadsheetApp.enableAllDataSourcesExecution();
spreadsheet.getCurrentCell().getDataSourceTables()[0].refreshData();
};
and this
function refresh() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A1').activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Master Worker Details Database'), true);
SpreadsheetApp.enableAllDataSourcesExecution();
spreadsheet.getCurrentCell().getDataSourceTables()[0].refreshData();
};
The problem only happens when I try to refresh the data connection using Macro. If I refresh it manually, it's okay.
I already try to follow the step explained here but the error still exist. Here is the script that I modified based on the explanation.
{
"timeZone": "America/New_York",
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "BigQuery",
"serviceId": "bigquery",
"version": "v2"
},
{
"userSymbol": "Drive",
"serviceId": "drive",
"version": "v2"
}]
},
"exceptionLogging": "STACKDRIVER",
"sheets": {
"macros": [{
"menuName": "refresh_master_worker_database",
"functionName": "refresh_master_worker_database"
}]
}
}
[UPDATE - 27 NOVEMBER 2019]
I already fix the error using this method <LINK>.