It’s been a few years since I first created the Goa library. Initially it was mainly to provide OAuth2 authorization and authentication to be able to access Google APIS and services unavailable via App Script. Nowadays of course, most of that can easily done by adding scopes to your appsscript.json manifest.

However Goa supports services other than Google, and flows other than the usual 3 legged oauth2. This is just a refresher on how Goa works and how to use it using the Twitter 2 API as an example.

Page Content hide
1 Motivation

Motivation

Twitter now have a v2 API which uses Oauth2. For their previous API version, you could use Oauth1 or other less secure methods of authentication. Their implementation of Oauth2 is a little funkier than most, so it Goa needed a few more tweaks to support it. That reminded me that I hadn’t posted about it for a while, so here is a complete refresher on Goa, Oauth2 and Apps Script.

I’ll use Twitter as an example provider throughout this article, but it’s a similar process whoever the service provider is.

Why Oauth2 is needed

There are 2 functions of Oauth2

  • Authentication – making sure that you are who you say you are by having you login into a trusted source – a resource provider like twitter – before running a script on your behalf
  • Authorization – ensuring that the function your script is trying to perform on your behalf is one that it is allowed to

Authentication

Let’s say your script wants to access your twitter account. One way would be to somehow build your user name and password into your script. However that means

  • Anyone who saw your script would now know your twitter password
  • If you changed your password on twitter, you’d also need to change it in your script

OAuth2 aims to ensure that your script can get your resources securely from twitter without having to manage or even know you or your twitter credentials.

  • The script is allowed to access twitter by knowing credentials supplied by twitter (clientId and clientSecret)
  • The script oversees you logging in to twitter – and on successful login, twitter returns a code specific to your account using a callback url to your script which matches one that twitter is expecting the given clientId to be able to handle
  • The script uses that code to exchange for an access token when it needs to access twitter on your behalf. This access token can be used till it nears expiry, but it can be refreshed using a refresh token which the OAuth2 process provided in the initial stage

Authorization

OAuth2 handles authorization using ‘scopes’. These describe collections of the API and the authority to perform certain actions on them. Each API is different and has a different scheme for defining their scopes. OAuth2 combines the notion of scopes that permit access with authentication that identify a friendly actor to produce a token back to the API which allows a certain level of access to resources belonging to a given individual.

What is Goa

It’s an Apps Script library to allow a serial approach to authentication (proving who you are) and authorization (allowing access to required resources). In other words, your script doesn’t have to get involved in the mysteries of figuring out endpoints, handling callbacks, deciphering state digests, and refreshing the tokens that inhabit the world of Oauth2.

Goa 3 Legged oauth2 works like this

These are generally one off operations

  • Get credentials from your OAuth2 provider developer console
  • Tell Goa about them. Goa takes care of the nuances of each known provider’s rules for OAuth2.
  • Run a webapp which will give you a url to put in your developer console and login into your provider’s site via Goa

Then each time you need to access a provider resource

  • Ask Goa for a token to put in your request header. Goa keeps note of the latest token it received from your provider and gives you that if it hasn’t expired. If it has expired it will automatically and silently get a new one for you

Example

Let’s say you’ve already gone through the preparation steps and you have a script that needs a token to access a service.  You can run a server side script like this. If Goa detects that needs to go off and get a new access token because the old one has expired, it’ll do it automatically.

const sideTwitter = () => {

  // pick up a goa instance for the previously prepared 'twitter' package
  const goa = cGoa.make(
    'twitter query',
    twitterPropertyService()
  )
  if (!goa.hasToken()) throw 'Youll need to go through the consent webapp once to set up credentials'
  
  // an example twitter query
  const u = `https://api.twitter.com/2/tweets/search/recent?` +
  `query=SuperFetch&tweet.fields=created_at&expansions=author_id&user.fields=created_at`

  // goa.getToken() is a drop in replacement for ScriptApp.getToken()
  const response = UrlFetchApp.fetch(u, {
    headers: {
      authorization: 'Bearer ' + goa.getToken()
    },
    method: "GET",
    muteHttpExceptions: true
  })
  console.log(response.getContentText() )

}
const twitterPropertyService = () => PropertiesService.getUserProperties()
server side tokens

Preparation

You’ll need the cGoa library added to your script – details at the end.

These are steps you’ll normally need to do just once.

This is using the Twitter developer console, but all oauth2 providers have a similar console in which to do all of this.

Go to twitter developer console and create an app

Edit your app settings

twitter app settings

In Settings, upload a logo if you have one, or just leave the default.

Here’s the twitter/goa logo in case you want to use it

goa twitter oauth2 apps script

 

 

Keys

In Keys and Tokens, go down to the Oauth2 section and get your clientId and clientSecret. You don’t need to bother about the other stuff on this page – that’s for other kinds of less secure authentication.

twitter oauth2 id and secret goa

Turn Oauth2 on

By default OAuth2 isn’t on – turn it on.

twitter oath2 settings

Setting up the credentials in Apps Script

Now we’ll go over to your Script, and set up the client id and secret in a property store. Which property store to use depends on the scenarios your use case will support, and I’ll touch on later, but quite often it’s going to be in the UserProperties Store.

create and run a once off script

  • the clientid and secret from the twitter developer console
  • some name you’ll use to refer to this credential set later
  • scopes that will authorize access to the twitter resources you need to access. I’m going to use this to do twitter queries, so these are the scopes I need. You’ll find all the twitter API scopes here.
 const twitterPropertyService = () => PropertiesService.getUserProperties()
 
 cGoa.GoaApp.setPackage (twitterPropertyService (), { 
    clientId : "xxxxx",
    clientSecret : "xxxxx",
    scopes : ["tweet.read","users.read"],
    service: 'twitter',
    packageName: 'twitter query'
  });
setting up apps script one off initializer

Run the script – you won’t need it again so when you’re finished testing, delete it from your script so as not to accidentially expose these credentials.

create a once off doGet function

In order to get the auth process going (Run a once off webapp which will give you a url to put in your developer console and login into your provider’s site via Goa), we’ll need a temporary simple web app.

// run this once off to get authorized
function doGet(e) {

  const goa = cGoa.make(
    'twitter query',
    twitterPropertyService(),
    e
  )

  // it's possible that we need consent - this will cause a consent dialog
  if (goa.needsConsent()) {
    return goa.getConsent();
  }

  // get a token
  const token = goa.getToken()

  // 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?';

  // now we can use the token in a query or just leave it there registered for future server side use
  return HtmlService.createHtmlOutput(`Got this access token ${token}`) 

}
one off webapp

Deploy the webapp

The IDE test deployment selection is fine for this. Click on the link it shows and it’ll take you into a dialog like this if it detects that it’s necessary to get consent.

That will bring up this consent dialog (the checkbox is to allow tokens to be sliently refreshed without and further human intervention)

dialog

Copy the Redirect URI from the dialog

Enter redirect URI in Twitter console

Paste that redirect URI from the consent dialog into your Twitter developers console so that when Twitter receives the request from your script and returns the authentication code it knows it’s definitely returning it to a valid script associated with your clientId.

You’ll find this under the Oauth2 settings that you turned on earlier.

You can usually have multiple redirect URIs associated with the same client, allowing you to create multiple projects using the same credentials.

twitter console redirect uri goa oauth2

Complete the consent dialog

Now that twitter knows that it can respond to your script safely, you can complete the consent dialog from your webapp  with the Start button, and twitter will (possibly ask you to login to twitter if you’re not already logged in and)  present you with this dialog

twitter login oauth2 goa

 

 

 

Get your access token and use it

If this is actually your web app you can go ahead and use the access token right away. In any case, it’s ready to be used now and the future by any web apps or server side scripts in your Apps Script project without any further action.

get access token

You can remove this web app and the once off credential function now.

 

Property Services

Here’s a guide on which property service to use.

  • If the script is to run as you – ie. access a resource belonging to you, and only you will be running the script, then use UserProperties – you’ll give access to your resource the first time you run it.
  • If the script is to run as you – ie. access a resource belonging to you, but others will be running the script accessing your resources then use ScriptProperties – you’ll give access to your resource the first time you run it.
  • If the scipt is to run as the user accessing the script – then it’s a little more complex as the credentials will need to be cloned to each new user for them to login into and give access to their resource the first time they use it while keeping individual tokens private to them. To support this scenario, initialize goa once off in ScriptProperties, and make the code below the first thing you do in your script. Goa will clone the credentials to the user’s property store the first time it sees them, will force an authentication and thereafter will maintain a separate thread of access/refresh tokens for each user.
  // clone credentials for each new user it comes across to their own provate userproperty store
  cGoa.GoaApp.userClone( 
    'twitter query', 
    PropertiesService.getScriptProperties() , 
    PropertiesService.getUserProperties()
  );
  // now we can use goa as normal and it will be specific to the logged on user
  const goa = cGoa.make(
    'twitter query',
    PropertiesService.getUserProperties(),
	e
  )
cloning for each user

There may be a reason to use DocumentProperties as well, but I can’t think of one for now.

Next

You may have come across my posts on SuperFetch – a proxy enhancement to Apps Script UrlFetch. I have a Twitter V2 API plugin for SuperFetch in the works that I’ll write up shortly in another article, and we’ll be using goa as a tokenService for that plugin.

Links

cGoa library 1v_l4xN3ICa0lAW315NQEzAHPSoNiFdWHsMEwj2qA5t9cgZ5VWci2Qxv2

IDE

Github

Related

goa twitter oauth2 apps script

Apps Script Oauth2 – a Goa Library refresher

It's been a few years since I first created the Goa library. Initially it was mainly to provide OAuth2 authorization ...
Read More

Goa v8 changes and enhancements

v8 and other HTML service changes meant I had to make a few small changes to cGoa. The good news it's ...
Read More

Goa in a sidebar

This describes how to implement goa in a sidebar. The example will assume that the authorization process should be repeated ...
Read More

Automatic UI support for OAUTH2 Goa dialogs

There's always a little bit of work needed if you are planning to do an OAUTH2 flow that might need ...
Read More

How OAuth2 works and Goa implementation

Oauth2 for Apps Script in a few lines of code (which you should read first for background) has many pages of ...
Read More

Using multiple service accounts to work across projects and lock down permissions with Apps Script and Goa

I use Cloud storage quite extensively as it's a great way to share data across platforms and projects. Apps Script ...
Read More

Hitching a ride on Goa’s property store

Goa is a library to simplify Oauth2 with both Google services and other Oauth2 providers, many of which are natively ...
Read More

Adding custom services to goa

Goa knows how to talk to a number of different Oauth2 providers using various flavours and varieties of OAuth flow ...
Read More

Google Apps Script Oauth2 for Vimeo with Goa

The Vimeo Rest API is a simple, standard API. It's been added to the Goa library list of services. Goa ...
Read More

Google Apps Script Oauth2 for quickbooks with Goa

The quickbooks Rest API is a simple, standard API. It's been added to the Goa library list of services. Goa ...
Read More

Goa and the Classy API

The Classy Rest API uses OAuth2 a little like a Service Account, which means there's typically no user dialog. It uses a ...
Read More

Google Datastore service for Goa using service account examples

This describes how to authenticate with Google Datastore using Goa along with a service account, as described in Oauth2 for Apps ...
Read More

Shoeboxed service for Goa examples

This describes how to authenticate with Podio using Goa, as described in Oauth2 for Apps Script in a few lines of ...
Read More

Reddit service for Goa examples

This describes how to authenticate with Podio using Goa, as described in Oauth2 for Apps Script in a few lines of ...
Read More

Podio service for Goa examples

This describes how to authenticate with Podio using Goa, as described in Oauth2 for Apps Script in a few lines of ...
Read More

Microsoft Live service for Goa Examples

This describes how to authenticate with Microsoft Live using Goa, as described in Oauth2 for Apps Script in a few lines ...
Read More

Soundcloud service for Goa examples

This describes how to authenticate with Soundcloud using Goa, as described in Oauth2 for Apps Script in a few lines ...
Read More

Google Datastore service for Goa examples

This describes how to authenticate with Google Datastore using Goa, as described in Oauth2 for Apps Script in a few lines ...
Read More

Asana service for Goa examples

This describes how to use the Asana service to authenticate with Asana using Goa, as described in Oauth2 for Apps Script ...
Read More

Goa services and customization

This describes how to set up new (or examine existing) services using the Goa library as described in Oauth2 for Apps ...
Read More
goa twitter oauth2 apps script

Apps Script Oauth2 – a Goa Library refresher

It's been a few years since I first created the Goa library. Initially it was mainly to provide OAuth2 authorization ...
Read More
SuperFetch

SuperFetch plugin – Firebase client for Apps Script

Frb is a SuperFetch plugin to easily access a Firebase Real time database. SuperFetch is a proxy for UrlFetchApp with ...
Read More
SuperFetch

SuperFetch plugin – iam – how to authenticate to Cloud Run from Apps Script

SuperFetch is a proxy for UrlFetchApp with additional features - see SuperFetch - a proxy enhancement to Apps Script UrlFetch for ...
Read More
SuperFetch

SuperFetch – a proxy enhancement to Apps Script UrlFetch

I've written a few articles about JavaScript proxying on here, and I'm a big fan. I also use a lot ...
Read More
SuperFetch

Apps script caching with compression and enhanced size limitations

Motivation Caching is a great way to improve performance, avoid rate limit problems and even save money if you are ...
Read More

Simple but powerful Apps Script Unit Test library

Why unit testing? There are many test packages for Node (my favorite is ava) and there are also a few ...
Read More