OAuth2 for Apps Script in a few lines of code

When I first started working with OAuth2, some years ago it was super complicated. Since that time, Apps Script has added a few capabilities which makes it possible to create a library with a minimal footprint in the App that uses it. My previous library, cEzyOauth2, like some others, contained a number of functions to service these complications (EzyOauth2 patterns), meaning that scripts using the library needed a fair amount of boilerplate code included in addition to the library.

This new library, that I call Goa, has these main features.

The 'in app' pattern is just a few lines of code.

No need to worry about handling callbacks. The new pattern manages the process behind the scenes.

Knows how to authenticate to a large number of services, such as Google, Microsoft Live, Github, Soundcloud, Reddit and many others.

Can handle both regular OAuth2 flow and service accounts.

Refreshing expired tokens in automatic and doesn't generate a dialog.

Credentials and token handling information are stored in the properties service and, each are identified by a unique name

Can handle authentication flows to multiple services in the same app.

Authentication dialogs can be webapp, sidebars or dialogs.

Authorization can be for either 'user running script' and 'script owner'

It's compatible with cEzyOauth2 and can use the same credentials.

It also supports jwt for firebase authorization

The library, cGoa, is available under this project key, or on github. All the tests described for this topic are also available on github.

MZx5DzNPsYjVyZaR67xXJQai_d-phDA33

Note:

In August 2016, the getProjectKey method was marked as deprecated, so the goa library (v22 and above) has been updated to use the scriptid rather than the projectKey for redirectUrl purposes.

for a quick run through of multiple scenarios using Google Apis, take a look at this summary

Quick summary of all OAuth2 scenarios

Goa cheat sheet

Or these more detailed tutorial slides

Goa tutorial

Goa tutorial

Some walkthroughs

Example

Typically, an authentication dialog is needed only once in the script lifecycle. Thereafter (if the API allows it), tokens will be refreshed automatically in the background. Service Accounts never need a dialog.

For this example, a token that has been created by an authentication dialog (for Microsoft OneDrive) will be refreshed as required and returned.

// 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);

}

A Goa authentication dialog looks like this.

Clicking Start will kick off the familiar Google Authorization screen.

Setting up the credentials

Each service will have its own dashboard for application credentials. Google has the developer console. You'll notice that the redirect Url for your script is shown in the Goa dialog. This is the one that should be entered into the developer console for the appropriate service.

A one time setup for each credential set looks like this. Here's one for GitHub. Note that Google APIS can take their credentials directly from a downloadable file.

var propertyStore = PropertiesService.getScriptProperties();

cGoa.GoaApp.setPackage (propertyStore ,{

clientId : "7------------0c",

clientSecret : "3------------------d",

scopes : [

'gist',

'repo'

],

service: 'github',

packageName: 'githubgoa'

});

Google Scope shortcuts.

Scopes are included in the package, and can be defined using the fully qualified Google scopes, such as

Google Service accounts

Using service accounts is no different that the regular oAuth flow, except there is never an authentication dialog. Refreshing is automatic just before. Here's an example of using the datastore with a service account.

// This is a webapp, so your function should return the HtmlOutput result of your process

if (!goa.hasToken()) {

throw 'for a non webapp version - first publish once off to provoke a dialog - token will be refreshed automatically thereafter';

}

// do a test - passing the token and any parameters that arrived to this function

Logger.log (testDataStore (goa.getToken(), goa.getParams() ));

}

The setup for a service account is different in the Developer console. You should download the JSON file containing the private key as advised when you set up the access, take a note of its fileId, and do a one time set up like this. Once you have done this one time setup, the file is no longer referenced as its contents are stored in the selected Properties Service.