Authentication of googleAnalyticsR with gcloud user on Jupyter

Thanks to a tweet from Lak, he highlighted another way to authenticate purely online when using notebooks e.g. not uploading a token from an offline R session.

Lak documents this in this helpful blogpost

It involves using the Terminal to get user access from the authentication within GCP.

  1. Create an OAuth2 client ID (Other) for the project running the notebook at this link https://console.cloud.google.com/apis/credentials
  2. Save the clientId JSON and upload to the Jupyter base directory (here assumed you name it jupyter_client_id.json)
  3. Make sure the APIs you want to authentication with are activated for that project e.g. Google Analytics Reporting API
  4. Make a Terminal in Jupyter via File > New > Terminal and issue the below commands to login via the browser, and print the access token (hint: you can press SHIFT and right click in terminal to copy/paste if CTRL+C and CTRL+V
# https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login
gcloud auth application-default login \
    --client-id-file jupyter_client_id.json \
    --scopes=https://www.googleapis.com/auth/analytics.readonly,https://www.googleapis.com/auth/analytics

## access the URL, login and create a verification code, paste in console.

## view then copy-paste the access token, to be passed into the R function
gcloud auth application-default print-access-token
  1. Use the following function to take the access token. This will be in googleAuthR version > 0.7.9000
In [1]:
gar_gce_auth_default <- function(access_token, 
                                 scopes, 
                                 cache_file = "gcloud.auth"){
  
  json_creds <- jsonlite::fromJSON('~/.config/gcloud/application_default_credentials.json')
  
  token_formatted <-
    httr::Token2.0$new(app = httr::oauth_app("google", 
                                 key = json_creds$client_id, 
                                 secret = json_creds$client_secret),
                       endpoint = httr::oauth_endpoints("google"),
                       credentials = list(access_token = access_token,
                                          token_type = json_creds$type,
                                          expires_in = NULL,
                                          refresh_token = NULL),
                       params = list(scope = scopes, type = NULL,
                                     use_oob = FALSE, as_header = TRUE),
                       cache_path = FALSE)
  
  options("googleAuthR.client_id" = json_creds$client_id,
          "googleAuthR.client_secret" = json_creds$client_secret,
          "googleAuthR.scopes.selected" = scopes)
  saveRDS(token_formatted, cache_file)
  
  message("Authenticated. Token saved to ", cache_file)
  
  token_formatted
  
}

An example token copy-pasted from the terminal is below. Pass that and the scopes for the API into the function above to create the token

In [2]:
at='ya29.XXXXXOgi2Zyl0PYU-mwZseSWXXXXXiQqxwCCalVMgRMcoXRn5fF2PH_Rz4fltI16O10zgh-RVN'
scopes = c('https://www.googleapis.com/auth/analytics.edit,https://www.googleapis.com/auth/analytics')
token <- gar_gce_auth_default(at, scopes = scopes)
Authenticated. Token saved to gcloud.auth

Once the token is available, you can use pass it in directly in the ga_auth() function, or via the filename it has been saved under (by default gcloud.auth)

In [6]:
library(googleAnalyticsR)
ga_auth(token)

# can now list accounts, get data etc.
accs <- ga_account_list()
head(accs)
Token cache file: 
accountIdaccountNameinternalWebPropertyIdlevelwebsiteUrlwebPropertyIdwebPropertyNametypestarredviewIdviewName
79301104 cloudyr 118427305 STANDARD http://cloudyr.github.io UA-79301104-1 the cloudyr project WEB NA 123875646 All Web Site Data
54516992 Demo Account 87479473 STANDARD https://shop.googlemerchandisestore.comUA-54516992-1 Google Merchandise Store WEB NA 92320289 1 Master View
54516992 Demo Account 87479473 STANDARD https://shop.googlemerchandisestore.comUA-54516992-1 Google Merchandise Store WEB NA 92324711 2 Test View
54516992 Demo Account 87479473 STANDARD https://shop.googlemerchandisestore.comUA-54516992-1 Google Merchandise Store WEB NA 90822334 3 Raw Data View
73050356 GDE Tracking 110873793 STANDARD http://gde-websites.com UA-73050356-1 GDE Tracking WEB NA 115760903 Bot excluded
73050356 GDE Tracking 110873793 STANDARD http://gde-websites.com UA-73050356-1 GDE Tracking WEB NA 115751114 RAW DATA
In [4]:
viewId <- 81416156
gadata <- google_analytics(viewId, 
                           date_range = c("30daysAgo", "yesterday"), 
                           metrics = "sessions", dimensions = "source", 
                           order = order_type("sessions", "DESCENDING", "VALUE"))
head(gadata)
2019-06-10 13:31:26> Downloaded [81] rows from a total of [81].
sourcesessions
google 5182
(direct) 1625
t.co 179
github.com 111
cran.r-project.org 47
shinyapps 40

Authentication via JSON service account

One other alternative which is better for long-term production use it to generate a service account key.

  1. In the same place you generated the OAuth2 credentials create a service account key here
  2. Download and upload to the Jupyter instance. Protect this key as it gives access.
  3. The key will have an email associated with it. Add this as a user to your Google Analytics account you want to interact with.
  4. Use googleAuthR::gar_service_auth() to authenticate.

This has more details on the googleAnalyticsR website here

In [5]:
sessionInfo()
R version 3.5.1 (2018-07-02)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)

Matrix products: default
BLAS: /opt/anaconda3/lib/R/lib/libRblas.so
LAPACK: /opt/anaconda3/lib/R/lib/libRlapack.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] bindrcpp_0.2.2         googleAnalyticsR_0.5.0 RevoUtils_11.0.1      
[4] RevoUtilsMath_11.0.0  

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.18      bindr_0.1.1       magrittr_1.5      tidyselect_0.2.4 
 [5] uuid_0.1-2        R6_2.2.2          rlang_0.3.4.9003  stringr_1.3.1    
 [9] httr_1.3.1        dplyr_0.7.6       tools_3.5.1       googleAuthR_0.6.3
[13] htmltools_0.3.6   digest_0.6.15     assertthat_0.2.0  tibble_1.4.2     
[17] crayon_1.3.4      IRdisplay_0.5.0   tidyr_0.8.1       purrr_0.2.5      
[21] repr_0.15.0       base64enc_0.1-3   curl_3.2          IRkernel_0.8.11  
[25] glue_1.3.0        memoise_1.1.0     evaluate_0.11     pbdZMQ_0.3-3     
[29] stringi_1.2.4     pillar_1.4.1.9000 compiler_3.5.1    jsonlite_1.5     
[33] pkgconfig_2.0.1