I have a GMail AddOn that uses OAuth2 for authorization of an external service. When starting the AddOn, I check if the user already has an access token by calling oauthService.hasAccess()
. If the user doesn't have a token, then I'll show a card that says "you need to authorize the service".
The card contain a link built like this:
section.addWidget(CardService.newTextButton()
.setText("Authorize MyService")
.setAuthorizationAction(
CardService.newAuthorizationAction()
.setAuthorizationUrl(authorizationUrl)
));
When the user clicks on the "Authorize MyService" button, a popup window appears and a spinner appears in the old card. Then the user logs into MyService, Authorizes access, and my AuthorizeCallback
gets called with the token. I store the token, and return a HtmlPage that just closes itself.
The spinner in the original card stops spinning. However, the AddOn does not reload. This suggests that there is something preventing the AuthorizationAction card from reloading when the authorization is completed. Any suggestions what that might be?
I want the AddOn to reload because then the entrypoint function will discover that now oauthService.hasAccess()
returns true
, and then will show the normal "you are authorized" card (and start processing the email to MyService).
Thanks for your help!
There might be a better way to do this but this is how I solved it.
First, instead of using setAuthorizationAction
use setOnClickAction
and set a function name.
section.addWidget(CardService.newTextButton()
.setText("Authorize MyService")
.setOnClickAction(CardService.newAction().setFunctionName('loginAction'));
loginFunction
will return an ActionResponse
. It will have a Navigation
and OpenLink
associated with it.
function loginAction(){
var nav = CardService.newNavigation().pushCard(getLoginStepsCard());
return CardService.newActionResponseBuilder()
.setStateChanged(true)
.setNavigation(nav)
.setOpenLink(
CardService.newOpenLink().setUrl(getLoginUrl()
)
.setOnClose(CardService.OnClose.RELOAD_ADD_ON)
.setOpenAs(CardService.OpenAs.OVERLAY)).build();
}
This will open the login popup. getLoginUrl
will return OAuth login URL. getLoginStepsCard
will return a card containing some info. In my case, I'm showing the steps required to log in, show whatever you want.
Inside authorize callback function, save your token and don't close the popup immediately. Closing the popup worked while I was testing (using HEAD
) but it didn't work for versioned deployment. The problem was it takes a few seconds for PropertiesService
to save the token. Just wait a few seconds (I use a setTimeout
of 5s) and close the pop-up or ask the user to close it. Add-on will reload and PropertiesService will have your token.
I hope this helps. It works for me and I have published my addon ;)
As mentioned in @AKT's answer, the core problem here is that the authorization callback is saving the token to properties, which don't replicate instantly to all Apps Script backends. So although the auth flow has been completed, when the add-on reloads it is still seeing the stale properties which show that it hasn't.
One way to work around this is to wait longer before closing the popup (and refreshing the add-on sidebar). A better option seems to be to ensure you are setting a cache on your OAuth service:
.setCache(CacheService.getUserCache())
This adds an additional caching layer that replicates faster, which seems to work around this issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With