How to Subscribe to GSuite and Google Workplace Notifications

How to Subscribe to GSuite and Google Workplace Notifications

Reading Time: 8 minutes
Prototype Build:
60 minutes (accounts, configuration, debugging)
Download+Customize:
2 minutes
Collective Time Saved:
days

Google provides an array of APIs for all manner of its services. When we think of Google’s user productivity and collaboration tools for business, we think of G Suite. G Suite is now called Google Workplace, but the tools and APIs we know and love are the same. Google Admin allows for excellent visibility into users’ actions with its Security, Report, and Alert Center pages, but how do you extend that functionality to build your own custom workflows for specific types of events? Previously we’ve looked at interacting with G Suite APIs here but now let’s focus on subscribing to “push notifications” via webhooks. Let’s take a look at how to subscribe to a G Suite endpoint and receive webhooks for user account events. This will let us build custom workflows and tailored security responses for a range of scenarios.

G Suite is rebranding to Google Workspace

G Suite / Google Workplace Automation and APIs

When diving into any API, the first concerns tend to be:

  1. Where and what sort of documentation does the API have?
  2. What specific endpoint(s) can I access?
  3. How do I authenticate?
  4. Are there any prerequisites, limitations, or ‘gotchas’ ?
  5. What tooling can I use to quickly prototype and test?

G Suite / Google Workspace API Documentation

  • Main G Suite / Google Workplace API documentation hub here.
  • REST API / scripting resources here 
  • Google APIs explorer here.
  • G Suite / Google Workplace Admin SDK for Reports API here.

G Suite / Google Workspace Reports Endpoint(s)

As we will be using the Reports API, the endpoint we will interact with most is the following to which we will be appending the “watch” command to create a “channel” or subscription to a specific event type


https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/[event_type]/watch

G Suite / Google Workspace API Authentication

API credentials are set up on a per-project basis. This means you are required to create a specific project name before creating API credentials. This is performed here: https://console.developers.google.com/ with a subsequent visit to https://console.developers.google.com/apis/credentials once you have created a project.

There are three critical steps here to ensure an efficient and successful outcome in terms of authentication.

Note: We will be using OAuth 2.0 to authenticate to Google’s APIs; however, we will use a “service account” and 2-legged server-to-server authentication (rather than a 3-legged one involving any interaction with a user). Additionally, we will request an OAuth grant-type of jwt-bearer, which will produce a JWT token. We will then use this token as our OAuth access token (in the header of our API calls). This means our automation will not need to engage with any refresh token requests nor interactive authorizations. An example diagram is provided by Google here. Now, let’s complete the three steps required to support a successful authentication and authorization:

  1. Generate a “Service Account” from the console under “APIs & Services > Credentials” and ensure you create and save an active key. Once you download the JSON data for it (keep safe as we will need this later), you will not be able to do so again. You are not required to enable “Domain Wide Delegation” at this point. By creating a “Service Account” you will also see there is an associated and non-editable “OAuth 2.0 Client ID” entry created. More information on the process can be found here.
  2. Ensure you have added your domain (or Tines tenant domain) to the “APIs & Services > Domain verification” section and complete the requirements there; otherwise, webhooks will not be approved or sent to our automation.
  3. Add the “Service Account”’s Unique ID (available here) to your Admin Console under “Main Menu > Security > API Controls” but ensure you add the following two OAuth scopes listed below (comma-delimited). A full list of available scopes can be found here.

https://www.googleapis.com/auth/admin.reports.audit.readonly,
https://www.googleapis.com/auth/admin.reports.usage.readonly

G Suite / Google Workspace Reports API Limitations

  • You must verify the domain you wish to send webhooks to in Google Search Console.. 
  • You must also renew your desired push notification subscriptions as they have an expiration time. This expiration is different per endpoint or service (the Reports API push expiration is 6 hours). This means we will also have to automate the re-subscription to our specific event type for our “channel”. 
  • Additionally, there are lag times on the freshness of data. The Reports API ‘User Accounts’ lags by a few minutes, and while some APIs are real-time, others may take 1-3 days, so be warned! The metrics for data retention and lag are here.

Tooling

cURL on the CLI is one way to test our JWT token request and subsequent calls. Postman has a nicer fully-fledged GUI, and of course, you could use your preferred language of choice, but today we will be using Tines. Tines has native support for JWT credentials (allowing us to generate and use tokens with a single and straightforward step from anywhere within our workflow), and it also enables rapid, reusable, and shareable workflows. 

Note: You can quickly receive a free, fully functional, no-strings Tines trial here.

Quick Setup Up

Step 1. Creating JWT Credentials

In Tines, go to “Credentials” and then “+ New Credentials” to create a new credential with the below details:

  • Type: JWT
  • Credential Name: Google
  • Algorithm: RSA256
  • Payload:

{
 "iss":"donal-blog-gsuite-apis@speedy-backbone-292412.iam.gserviceaccount.com",
 "sub":"donal@tines.io",
"scope":"https://www.googleapis.com/auth/admin.reports.audit.readonly https://www.googleapis.com/auth/admin.reports.usage.readonly",
 "aud":"https://www.googleapis.com/oauth2/v4/token"
}
  • Auto generate ‘iat’ (Issued At) & ‘exp’ (Expiration Time) claims: ticked/yes
  • Private key: <paste the contents of the private_key beginning with ‘-----BEGIN PRIVATE KEY-----’ and ending with ‘-----END PRIVATE KEY-----\n’>
  • Share credential: <empty>

Note: Ensure you replace the “payload” iss field with your service account’s email address and also replace the sub field with your email address.

Step 2. Testing the JWT Credentials

In Tines, create a new story and then search the templates (on the left-hand side) for the ‘Google Bearer’ agent (as per below). Add that template by dragging and dropping it to the main storyboard.

Tines: Find and add the “Google Bearer” agent template. 
Tines: Find and add the “Google Bearer” agent template. 

Now click the agent, and when you run “▷” it, you should get a token in the response (visible from the right-hand side panel under “Events” when you hover over the Event ID and click “Show”.


{
  "get_a_google_bearer_token": {
    "body": {
      "access_token": "ya29.a0AfH6SMCaj8sQUMCb1TsdqX32mujhRr0f4UouWC-t9VLdqCSwZwIdIG83YAoOKkNWSQ5t9UnAt5jfELpXfBCowLGl0w94zIvOpIR21Zsa7i3lTpGPX6s1cMQJxoAIT97IG6DvvLvI3V4VjQ45PsHcjRt2Ivp51c2HT0PLeU2C2DHM8zIeNUMTYFojT0VeX4bgKPX1QTjqvzYDoZ7fcnwJ",
      "expires_in": 3599,
      "token_type": "Bearer"
    },
    "headers": {
      ...
    },
    "status": 200
  }
}

Step 3. Using the JWT Credentials

We can now happily utilize this token. We don’t immediately care about its expiry in 3599 seconds (i.e. 1 hour) as we can complete whatever we need to do within an hour. However, the next step of watching a resource will have a time expiration challenge! Let’s move on to asking the Reports API to watch all the user accounts on our domain for certain types of account changes. But, just before we do that, let’s put our receiving Webhook agent in place as we will require one of its attributes.

Drag an empty agent of the type Webhook onto the storyboard (using the left-hand side panel) and then click the agent to focus on it. Go to its “Summary” to see the actual webhook URL (as per below):

Tines: Empty Webhook agent for receiving, you guessed it, webhooks!
Tines: Empty Webhook agent for receiving, you guessed it, webhooks!

Make a note of your specific webhook URL as we will use it in the next part of our agent watcher story workflow. We will return to this webhook agent shortly, but for now, let’s complete our event subscription workflow.

Let’s add an empty HTTP agent below our Bearer Token agent and call it “Watch GSuite User Accounts Events”. Then join the bottom of the top agent to the top of the bottom agent by clicking and dragging a link (visible once you hover over the bottom of any agent)!

Tines: Empty HTTP agent, which we will customize for our subscription.
Tines: Empty HTTP agent, which we will customize for our subscription.

Now, let’s click the new “Watch GSuite User Accounts Events” agent and add in the fields below (using the Builder mode). We will update the url, payload and also add a header called “Authorization” which will reference the access token received from our previous agent. The url and format used relate to how we construct “Receive Push Notifications” for the Reports API (and what type of activity we wish to monitor). There is a range of options, but for now, we are going to watch all users and all user_account events. The user_account events are covered in detail here.

Note: Double curly brackets and curly brackets with a percent sign are a special way to reference variables, values, and filters in the Liquid templating language (one that Tines makes frequent use of).


{
  url: https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/user_accounts/watch
  content_type: json
  method: post
  payload: 
    {
      id: {% random 1000000000000000-9999999999999999 %}
      type: web_hook
      address: [your_webhook_url]
    }
  headers: 
    {
      Authorization: Bearer {{ .get_a_google_bearer_token.body.access_token }}
    }
}

Now, if we click run “▷” on our top Google Bearer token agent and then examine the latest event emitted by the Watch Gsuite agent, we should see the chain of responses from each agent. The second portion from the “watch_gsuite_user_accounts_events” includes confirmation of our request and has our previously supplied ID “2537345593403974”, with a new resourceID “h7md_uScTjB0O2f_FkWUQKrgR6g”, and expiration date in Epoch seconds “1603117386000”.


{
  "get_a_google_bearer_token": {
    "body": {
      "access_token": "ya29.a0AfH6SMBiciBUayN0jpaD3hLtRUKuJk8uaCroUOibxBl7xg48Na7CGnLS3wc6C-ihZWXtzzBslMpSAixymmywo9HR-dIhXCvWzOtcYXbLltNYWjjoGayyocU8bsap5hwet4O-v_zel2a4mi7MDXiRTMTMnIpYYKEqkfU0x1Wq6BywC6bdUOjJQjpdp5wgB2ilG47AAvZoI29eov-ZT_K9",
      "expires_in": 3599,
      "token_type": "Bearer"
    },
    "headers": {
      ...
    },
    "status": 200
  },
  "watch_gsuite_user_accounts_events": {
    "body": {
      "kind": "api#channel",
      "id": "2537345593403974",
      "resourceId": "h7md_uScTjB0O2f_FkWUQKrgR6g",
      "resourceUri": "https://www.googleapis.com/admin/reports/v1/activity/users/all/applications/user_accounts?alt=json&orgUnitID",
      "expiration": "1603117386000"
    },
    "headers": {
      "etag": "\"9T9vzOl0oqU3TCQ3eSvkwrTkXlbD64F_wxS6Ylj40QU/Idl49PiHd-7ZTMHJTOVmEu4OYiY\"",
      "content-type": "application/json; charset=UTF-8",
      "vary": "Origin, X-Origin, Referer",
      "date": "Mon, 19 Oct 2020 08:23:06 GMT",
      ...
    },
    "status": 200
  }
}

The date/time stamp from the API response says “Mon, 19 Oct 2020 08:23:06 GMT” but the expiration time for watching events (when converted from Epoch seconds) says “Mon, 19 Oct 2020 14:23:06 GMT”, which is precisely 6 hours later. We will need to refresh and reactivate this subscription before it expires if we want this to be an ongoing thing. We will achieve this with a Transformation agent set to mode “delay” for 21595 seconds (5 hours 55 seconds), and then we’ll join it back to the start with a simple wiring up of the agents into a loop! Let’s wire it up!

Tines: Standalone loop to deal with an expiration timer and restart the event “watching”.
Tines: Standalone loop to deal with an expiration timer and restart the event “watching”.

Putting it All Together

We now have an active subscription to the Reports API user_account events, and, other than informational sync messages, we will receive all the data we need in the subsequent webhooks. It is from this entry point (our previous Webhook agent) that we can now make decisions about what to do next, be it for alerts, sending interactive user messages, or even to trigger other actions or applications to perform related tasks for us. We can even chain our story workflows together to make them more modular and easily reusable.

Let’s add some more agents below to our WebHook agent and build a small but extensible story workflow that acts on the type of notification content we receive.

Tines: From webhook to triggers and actions, including IP checks, email, and modular stories.
Tines: From webhook to triggers and actions, including IP checks, email, and modular stories.

Initially, we only see the “sync” message from our “watch” request, but things get more interesting once someone changes their password, disables multi factor authentication, updates their recovery details, or changes their Advanced Protection state. Let’s do a quick password change and see what will happen…

Tines: Account password change flows through our workflow.
Tines: Account password change flows through our workflow.

The password change created an event and sent a notification to our webhook agent. We can see the contents of this webhook below (including the fields we make decisions on, such as the actor involved and any specific events at play).


{
  "receive_webhook": {
    "body": {
      "kind": "admin#reports#activity",
      "id": {
        "time": "2020-10-19T13:28:36.696Z",
        "uniqueQualifier": "2247204315564511884",
        "applicationName": "user_accounts",
        "customerId": "C02sz61y7"
      },
      "etag": "\"UCgH-M2qpDHjINmaEvPOa_of7ms/nYgXVMgP7Inw9QFQsLO-Dc4oxs4\"",
      "actor": {
        "callerType": "USER",
        "email": "donal@tines.io",
        "profileId": "116204564155189261560"
      },
      "ipAddress": "37.228.209.228",
      "events": [
        {
          "type": "password_change",
          "name": "password_edit"
        }
      ]
    },
    "headers": {
      ...
    }
  }
}

In the story workflow, we also chose to send an email to the “actor” asking if this was indeed them. We could take any action we decide upon using predefined integration templates or by using fresh agents to talk to any RESTful endpoint you require. The email contains a “prompt” widget to ask the user if it was them. If it was not them, they should click the link, which continues our workflow.

Tines: Email to a user to confirm or deny whether the recent account change was them.
Tines: Email to a user to confirm or deny whether the recent account change was them.

Let’s say it wasn’t us, and we click the link! This continues the workflow below and emits a new event that we can match on to determine what further additional actions or steps to perform.

Tines: Story workflow continues and calls another story.
Tines: Story workflow continues and calls another story.

We now use another agent type called “Send To Story” to initiate a modular sub-story called “STS Initiate Incident Response”. This additional story could be anything from creating an incident in a case management system to beginning automated Threat Hunting.

Wrap Up

We’ve seen how to use server-to-server communications to subscribe to G Suite / Google Workspace event channels. If you want to stop watching a channel, you just need to POST the channel ID and resourceID to the “stop” endpoint (detailed here). There are many more endpoints you can watch as long as you have the right access to the required scopes. The story above is only a brief introduction to the flexibility and extensibility of building story workflows using Tines. The above story can be downloaded here to give you a headstart. You can, of course, construct or modify any story to suit your own needs, processes, or Standard Operating Procedures (SOPs); why not give it a go?


💡  What now ? If you’re unsure what’s next on your automation journey, grab a quick demo or ask us how we'd automate your use case ? Either way you can experiment with a free, no strings, fully-functional trial to see what's possible...

Donal O Duibhir
Donal O Duibhir
Security Engineering, Tines