Investigating user delegated OAuth tokens in Google Workspace - a ride along
A brief discussion about OAuth tokens, how they are used, reasons you might want to review them, and then an exploration of how you might start actually doing this in Google Workspace, which (TL;DR) turns out to not be neither trivial or easy to automate.
What are user delegated OAuth tokens?
When users want to integrate a 3rd party app (like Zoom, Slack, Zapier, etc. etc.) with Google Workspace (or Office 365, or almost any SaaS platform these days really), they provide that app with a token (an OAuth2 token to be specific). This token can be used by the 3rd party to connect to your Workspace to gain access to that user’s data instead of a password.
You might recognise screens like this which actually do the job of granting these tokens.
That list of permissions is a human readable version of what are called scopes. Scopes limit what the 3rd party can do with the token. There are a number of ways you can limit the 3rd parties and scopes your users can authorise, and we’ll cover those in future blog posts - for now we are focussing on the existing tokens that have already been granted.
Why would you want to review these apps and tokens?
Essentially there are quite a few things that can go wrong here, which is not unexpected when we are talking about granting 3rd parties access to a core business platform like Workspace - and perhaps in something like an ordering of obviousness they are things like:
Consent phishing - where an attacker uses a malicious app linked in an email to trick users into giving them access to the user's data.
Useful but malicious apps - as we’ve seen recently in browser extensions (especially chrome), mobile apps (especially android, pattern forming here?), PC software, etc. etc. there are a number of criminals who develop legitimately useful (or at least vaguely useful looking) software that is also used to get backdoor access to your data. This is even harder to spot in SaaS applications, because unlike browser extensions or mobile apps, you can’t inspect the code. And because Almost no SaaS apps expose good logs of what is done using these tokens, you can’t inspect what they are doing.
Supply chain - while supply chain attacks are all the rage these days, we’ve yet to see a really clear attack where an attacker has stolen specifically OAuth tokens from one of these 3rd parties and used them against their customers - at least to my knowledge (please tweet my wrongness @jacques_sec). This does not however mean this can’t or won’t happen - and in fact I’d be super surprised if this doesn’t happen in the next few years.
While there are a lot of things you might want to look at when reviewing an OAuth app, you will at least want to know who owns/publishes the app (who have you delegated access too), what permissions or access the 3rd party has to your data, and whether Google has reviewed and verified the app - so let’s use this blog to focus on that starting point.
Getting the basic token details
As a user you can look at your own Workspace tokens - where you’ll see a box like this for each integrated app:
You’ll see things like the authorised domain (diagrams.net in this case), the homepage of the app, and a description of the permissions granted by the scopes (though not the raw scopes themselves). Unfortunately, fairly basic information, like if the app has been verified by google is not available.
This page is also only available to view your own apps. Rather than trying to teach each of your users how to review OAuth apps, you may want to review these on behalf of your users, and let them get on with their jobs leaving your relationship with them intact. Google anticipated this, and actually allows you to get a list of these apps (or rather the tokens that grant them access) through the admin console in a couple of ways.
If you open a user’s profile in the admin console and click “connected applications” you’ll get something like this:
Beyond having to do this one user at a time - this is useful to see the display name for the application and the services which the app has access to. Unfortunately there is no information to show if the app has been verified by Google, and even worse nothing that links it to a specific publisher. At Push we publish quite a few apps ourselves I can tell you that the display name (“Google APIs Explorer” or “Slack” in the above example) is anything the author chooses, and so isn’t reliable at all unless the app has been verified (I’m assuming Google would reject look-alike or spoofed names here), but again you can’t tell here if the app has been verified by google - so on we go!
The admin console also provides security reports on token grants that look something like this:
Here we can see the raw scopes (you can find more info about the actual scopes in Google's API docs), the app name (display name as above) and the all important client_id that is, as far as I can tell, the closes we get to uniquely identifying an app under the hood. As a side note, it turns out that the first number sequence of the client_id is actually the project number of the Google Cloud Project which hosts the app (or technically which hosts the OAuth consent screen for the app). Still no verification status, and no way to figure out who published the app. Further down the rabbit hole we go.
Workspace Admin also has an API, and fortunately there is a tokens resource (see Google docs for Admin Directory API) and there is even an API explorer (which - strange loop warning - also uses OAuth tokens to grant itself access to the API), which give you the following:
Which actually gives you all the tokens for a user you specify. Not much here that is useful beyond what we got from the token report - we still just have display name, scopes, and the client_id - however, we can now at least automate the process of pulling all apps for all users without having to figure out which are still active after grants and revokes in the audit report.
At this point I was worried whether this would be possible as I couldn’t find any APIs that actually resolved the client_id to something more useful, so I started looking at ways to restrict installing apps instead. This led me to the Security > API controls > App access control panel in the admin console. This panel shows a list of all the trusted apps (which includes all the installed apps), and crucially if you click on the app you get something like the following:
Huzzah! - finally we have verification status, as well as an email address and links to various policies which can be used to identify the actual publisher of the app (my assumption here is that if the app is verified we can trust this information, but that might be something worth digging into a bit deeper, especially for apps that are not requesting sensitive or restricted scopes, both of which have increasingly thorough vetting).
Unfortunately this is not the end of the story. There are still a couple of problems here, firstly we can’t see which users granted which tokens - only how many users have active tokens. We could correlate this with the information in the user’s profile, but then you could have multiple apps using the same name as below:
This can be solved by referencing the client_id with the admin.directory.tokens.list API (as discussed above), but that brings us to my final problem - it’s going to be painful cross referencing as the data in the screenshot above is not available in any API I can find, so to automate this I guess we’re going screen scraping 🤦. If you know a better way - please tweet me (again @jacques_sec).
I’m planning to write future posts on this subject before I forget it all, and these will likely focus on understanding exactly what is possible using specific scopes in a more automated way than paging through endless docs, and more detail on doing in-depth security reviews of OAuth apps. Get in touch if either of these (or something related) would be of interest to you and we might re-prioritise!