Skip to content

Commit

Permalink
Fix: Add expiry to oauth arguments for refresh
Browse files Browse the repository at this point in the history
Currently the oauth flow does not do refreshes if the access token is expired, as Credentails() does't know when the access token expires, so it completely skips refreshing.

Credentails() will only refresh when a expiry datetime object is passed, so here we add an oauth argument for expiry, and pass it to Credentails().
  • Loading branch information
JichaoS committed Oct 17, 2023
1 parent da49600 commit ac5fbc1
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 3 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ A full list of supported settings and capabilities is available by running: `tap

`tap-google-analytics` supports two different ways of authorization:
- Service account based authorization, where an administrator manually creates a service account with the appropriate permissions to view the account, property, and view you wish to fetch data from
- OAuth `access_token` based authorization, where this tap gets called with a valid `access_token` and `refresh_token` produced by an OAuth flow conducted in a different system.
- OAuth `access_token` based authorization, where this tap gets called with a valid `access_token` and `refresh_token` produced by an OAuth flow conducted in a different system. To refresh the `access_token` with the provided `refresh_token` on demand, you must provide a valid `expiry`.

If you're setting up `tap-google-analytics` for your own organization and only plan to extract from a handful of different views in the same limited set of properties, Service Account based authorization is the simplest. When you create a service account Google gives you a json file with that service account's credentials called the `client_secrets.json`, and that's all you need to pass to this tap, and you only have to do it once, so this is the recommended way of configuring `tap-google-analytics`.

If you're building something where a wide variety of users need to be able to give access to their Google Analytics, `tap-google-analytics` can use an `access_token` granted by those users to authorize it's requests to Google. This `access_token` is produced by a normal Google OAuth flow, but this flow is outside the scope of `tap-google-analytics`. This is useful if you're integrating `tap-google-analytics` with another system, like Stitch Data might do to allow users to configure their extracts themselves without manual config setup. This tap expects an `access_token`, `refresh_token`, `client_id` and `client_secret` to be passed to it in order to authenticate as the user who granted the token and then access their data.
If you're building something where a wide variety of users need to be able to give access to their Google Analytics, `tap-google-analytics` can use an `access_token` granted by those users to authorize it's requests to Google. This `access_token` is produced by a normal Google OAuth flow, but this flow is outside the scope of `tap-google-analytics`. This is useful if you're integrating `tap-google-analytics` with another system, like Stitch Data might do to allow users to configure their extracts themselves without manual config setup. This tap expects an `access_token`, `refresh_token`, `client_id`, `client_secret` and `expiry` to be passed to it in order to authenticate as the user who granted the token and then access their data.

## Required Analytics Reporting APIs & OAuth Scopes

In order for `tap-google-analytics` to access your Google Analytics Account, it needs the Analytics Reporting API *and* the Analytics API (which are two different things) enabled. If using a service account to authorize, these need to be enabled for a project inside the same organization as your Google Analytics account (see below), or if using an OAuth credential set, they need to be enabled for the project the OAuth client ID and secret come from.

If using the OAuth authorization method, the OAuth flow conducted elsewhere must request at minimum the `analytics.readonly` OAuth scope to get an `access_token` authorized to hit these APIs
If using the OAuth authorization method, the OAuth flow conducted elsewhere must request at minimum the `analytics.readonly` OAuth scope to get an `access_token` authorized to hit these APIs.

### Creating service account credentials

Expand Down
11 changes: 11 additions & 0 deletions tap_google_analytics/tap.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import json
import logging
import sys
from datetime import datetime
from pathlib import Path
from typing import List, Tuple

Expand Down Expand Up @@ -78,6 +79,11 @@ class TapGoogleAnalytics(Tap):
th.StringType,
description="Google Analytics Client Secret",
),
th.Property(
"expiry",
th.StringType,
description="When the access token expires. ISO 8601 offset-naive UTC datetime string like '1980-01-01T00:00:00'",
),
),
description="Google Analytics OAuth Credentials",
),
Expand Down Expand Up @@ -119,12 +125,17 @@ class TapGoogleAnalytics(Tap):

def _initialize_credentials(self):
if self.config.get("oauth_credentials"):
expiry = None
if "expiry" in self.config["oauth_credentials"]:
expiry = datetime.fromisoformat(self.config["oauth_credentials"]["expiry"])

return OAuthCredentials(
token=self.config["oauth_credentials"]["access_token"],
refresh_token=self.config["oauth_credentials"]["refresh_token"],
client_id=self.config["oauth_credentials"]["client_id"],
client_secret=self.config["oauth_credentials"]["client_secret"],
token_uri="https://accounts.google.com/o/oauth2/token",
expiry=expiry,
)
elif self.config.get("key_file_location"):
with open(self.config["key_file_location"]) as f:
Expand Down

0 comments on commit ac5fbc1

Please sign in to comment.