Howto: Gargle Authentication in Jupyter

TL;DR: See the code snippet at the bottom of this post for the code needed to get this to work.

gargle is a great little library for the R programming language that implements several authentication mechanisms against Google accounts. It’s used to power useful integrations like googlesheets4, and googledrive that allow R scripts to load data out of Google cloud resources. I recently started trying out Tiller for managing my personal finances, and I wanted to access my data from a JupyterLab notebook. When running on the command line, or in RStudio, gargle helpfully executes the OAuth flow by running a little local webserver that processes the authentication flow. In my JupyterLab setup, the kernel isn’t running on my machine directly. I tried running googlesheets4’s gs4_auth, but got back:

Error in `gs4_auth()`:
! Can't get Google credentials.
ℹ Are you running googlesheets4 in a non-interactive session? Consider:
• Call `gs4_deauth()` to prevent the attempt to get credentials.
• Call `gs4_auth()` directly with all necessary specifics.
ℹ See gargle's "Non-interactive auth" vignette for more details:
ℹ <https://gargle.r-lib.org/articles/non-interactive-auth.html>

Attempting to use OOB OAuth #

Luckily, the OAuth standard recognizes that there may be cases where the OAuth flow can’t be done automatically via browser redirects. In these cases OAuth allows for “out of bounds” (OOB) authentication, where the application prints out a URL, you paste that URL in your browser, do the authentication flow, get a token, and then paste that token back into the application. Basically doing the typical flow “by hand”. gargle supports this option with the use_oob parameter. Here we pass it to gs4_auth (a googlesheets4 specific wrapper around gargle) and get:

Error in `gs4_auth()`:
! Can't get Google credentials.
ℹ Are you running googlesheets4 in a non-interactive session? Consider:
• Call `gs4_deauth()` to prevent the attempt to get credentials.
• Call `gs4_auth()` directly with all necessary specifics.
ℹ See gargle's "Non-interactive auth" vignette for more details:
ℹ <https://gargle.r-lib.org/articles/non-interactive-auth.html>

Again! Ugh! What’s going on here? Jupyter should be plenty “interactive” to do an OOB flow. Why won’t it work…

Interactive Sessions #

After a brief spelunking expedition, I found this line. gargle will refuse to execute the OAuth flow if it doesn’t think the session is interactive. It uses the is_interactive() function to make that decision. Turns out this function comes from rlang a standard suite of tools used by tidyverse packages. Luckily, it’s configurable, so I tried again, this time with a slightly more complex invocation:

rlang::with_interactive({ gs4_auth(use_oob=TRUE) })

And… The same error! Ugh!

Interactive Sessions, Again #

At this point I decided to turn on debug logs for gargle, and noticed that gargle was encountering a stop signal. Further spelunking tracked it down to a check in the httr HTTP client library. This library is wrapped by gargle, and it performs the underlying OAuth flow. Unfortunately, it uses a different (more standard) definition of an interactive session: the built-in interactive() function. Of course running interactive() in my Jupyter session showed my worst fears were reality:

> interactive()
FALSE

Cool.

Well, I guess I’m not running R directly. Maybe there’s some good reason that IRKernel isn’t recognized as interactive. Maybe there’s some option I can enable… Searching around turned up this issue from the IRKernel Github Repo, a 6 year old bug with the ominous line:

OK, this is pretty hard:

Turns out that R bases interactive solely on the --is-interactive flag passed on interpreter startup which restricts the ways that input can be provided, and breaks IRKernel. The IRKernel developers swiftly filed a feature request on R to make this more flexible, but that request has sat safely untouched for the intervening 6 years.

A Fix at Last #

Great! Well, luckily, the developers of httr left us one final hope. They wrapped the interactive builtin with another function called is_interactive (though notably, not the rlang provided is_interactive). Since this is R, maybe, we can just overwrite that function to do what we want, and everything will work great. We can use the built in assignInNamespace to perform this dubious action. Putting this together with our earlier hack for gargle, we get:

assignInNamespace("is_interactive", function() { TRUE }, "httr")
rlang::with_interactive({ gs4_auth(use_oob=TRUE) })

And, that’s the ticket! gargle, or maybe httr (I didn’t bother to check), prints out the authentication URL, and displays a textbox for us to type our authentication code into. Hooray!

 
1
Kudos
 
1
Kudos

Now read this

Random Linux Oddity #1: ru_maxrss is Inherited

These days I do roughly 100% of my development on and for systems running Linux. Since my work and personal interests are pretty “low level”, I have spent quite a bit of time investigating the weird, and surprising details of the Linux... Continue →