- The app asks for an authentication code
- This authentication code is returned to a redirect uri which has been previously agreed and set up in the App dashboard, between the service provider and you.
- This authentication code is exchanged for an access token, which is then used to authorize your access a protected resource until it expires.
- A refresh token can optionally be returned along with the access token. This refresh token can then be used to get a new access token without the need for an interactive dialog in the future.
- When the request for an authentication code is made, a state token is also sent. This state token includes various information which identifies which Apps Script function to call when a call back to the redirect uri is detected. Since the callback also returns the provided state token, Apps Script can call the given function.
- When this function is called, it is in a new context. This means that anything your script has done to this point is forgotten. It is this redirection and restart that cause most people problems when using OAuth2 at first.
The pattern
function doGet(e) { return doGetDataStore (e); }
var goa = cGoa.GoaApp.createGoa ('DriverDatastore_example',PropertiesService.getScriptProperties()).execute(e);
What does execute do?
- If it detects there is an access token available with some time left , it will do nothing.
- If there is no available access token, but there is a refresh token, it will refresh the access token and store it for future use.
- If there is no refresh token, then it needs to prepare for a fresh consent dialog.
Getting consent
if (goa.needsConsent()) { return goa.getConsent(); }
Goa will have arranged to be called back to the same function it was executed from. This means that after the consent is received and a token generated, it will pass through exactly the same code as before.
var goa = cGoa.GoaApp.createGoa ('DriverDatastore_example',PropertiesService.getScriptProperties()).execute(e);
if (goa.needsConsent()) { return goa.getConsent(); }
- goa.execute will detect that there is now an available access token and do nothing.
- goa.needsConsent will be false and, the flow will continue on.
The major benefit of this approach is that there is no need for a separate flow or special handling when a consent dialog is needed.
Getting the token
if (!goa.hasToken()) throw 'something went wrong with goa - did you check if consent was needed?';
var result = testDataStore (goa.getToken(), goa.getParams() ); // now return it as normal return HtmlService.createHtmlOutput (result.getContentText()) .setSandboxMode(HtmlService.SandboxMode.IFRAME);
Parameters
The final pattern
function doGetDataStore (e) { // this is pattern for a WebApp. // passing the doGet parameters (or anything else) // will ensure they are preservered during the multiple oauth2 processes // change this to whatever store & credentials name are being used var goa = cGoa.GoaApp.createGoa ('DriverDatastore_example',PropertiesService.getScriptProperties()).execute(e); // it's possible that we need consent - this will cause a consent dialog if (goa.needsConsent()) { return goa.getConsent(); } // if we get here its time for your webapp to run and we should have a token, or thrown an error somewhere if (!goa.hasToken()) throw 'something went wrong with goa - did you check if consent was needed?'; // This is a webapp doing whaever its supposed to do // getParams is used to retrieve the original parameters passed to this function var result = testDataStore (goa.getToken(), goa.getParams() ); // now return it as normal return HtmlService.createHtmlOutput (result.getContentText()) .setSandboxMode(HtmlService.SandboxMode.IFRAME); }
The redirect Uri
For convenience, Goa shows the redirect Uri it needs to be put into the App Dashboard, as in the example below. Just copy and paste it into the app dashboard or developer console if you are just setting the app up for the first time.
Sidebars and Dialogs
function sidebarDataStore (e) { // this is pattern for a WebApp. // passing the doGet parameters (or anything else) // will ensure they are preservered during the multiple oauth2 processes // change this to whatever store & credentials name are being used var goa = cGoa.GoaApp.createGoa ('DriverDatastore_example',PropertiesService.getScriptProperties()).execute(e); // it's possible that we need consent - this will cause a consent dialog in the sidebar if (goa.needsConsent()) { var html = goa.getConsent() .setTitle('oauth2 dialog for ' + goa.getPackage().packageName) .setWidth(300); SpreadsheetApp.getUi() // Or DocumentApp or FormApp. .showSidebar(html); } }
Here’s the dialog in a sidebar.
For more like this, see Oauth2 for Apps Script in a few lines of code.Why not join our forum, follow the blog or follow me on Twitter to ensure you get updates when they are available.