tidyverse / googledrive

Google Drive R API
https://googledrive.tidyverse.org/
Other
322 stars 47 forks source link

Feature request: Create equivalent of `with_subject()` from python google.oauth2.service_account #413

Closed fh-kpikhart closed 1 year ago

fh-kpikhart commented 1 year ago

The googledrive::drive_auth email param requires that the email used to auth is also the email address of the service account used to perform actions within the Google Drive. In python, we can use with_subject() to specify a different email address from the one used to auth. Is there an equivalent function in googledrive?

jennybc commented 1 year ago

Do you have a service account that has domain-wide delegation of authority? I think gargle (and therefore googledrive and other packages) basically can already do this or at least it's very close. But I am not allowed to have such a service account in my organization's workspace, so the friction for figuring this out in the abstract has always been too high. But if I am communicating with a motivated user that has the necessary setup, that might be the incentive I need to sort this out finally.

Roughly speaking, the experiment to start with is this:

token <- gargle::credentials_service_account(scopes = "{YOUR DESIRED SCOPES}", path = "path/to/your/service/account.json", subject = "{USER YOU WANT TO IMPERSONATE}")
fh-kpikhart commented 1 year ago

Yes, I have a service account that has domain-wide delegation. Thank you for pointing me to this function! I'm trying it out; will report back after I pair with someone on an error I'm bumping into down in httr:::init_oauth_service_account.

fh-kpikhart commented 1 year ago

Here's a brief update:

When using gargle::credentials_service_account with the subject param, we're hitting this error:

Error in init_oauth_service_account(self$secrets, scope = self$params$scope,  : 
  Unauthorized (HTTP 401).

Stepping through init_oauth_service_account line by line, I'm seeing that httr is making a POST call to google and getting this result:

Browse[2]> res
Response [https://oauth2.googleapis.com/token]
  Date: 2023-02-21 02:18
  Status: 401
  Content-Type: application/json; charset=utf-8
  Size: 188 B
{
  "error": "unauthorized_client",
  "error_description": "Client is unauthorized to retrieve access tokens using this method, or ...

Browse[2]> res %>% content()
$error
[1] "unauthorized_client"

$error_description
[1] "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."

So far I'm unable to figure out what is different between this code and our python implementation (using google.oauth2.service_account and googleapiclient.discovery), to explain why were getting this "unauthorized" error in R only.

fh-kpikhart commented 1 year ago

Brief update:

At this point, I think my feature request would be to support the subject arg in googledrive::drive_auth()

jennybc commented 1 year ago

Thanks for your continuing effort and sharing. I'm definitely interested in making this work and what you're doing is extremely helpful.

fh-kpikhart commented 1 year ago

No problem!

FYI, I can confirm that after adding the additional scope, we are able to successfully accomplish our use case with gargle::credentials_service_account()

jennybc commented 1 year ago

Very interesting! I'm not entirely sure yet how to act on this, but this is a very useful finding.

I mean: it is clear that drive_auth() will need to the ability to pass the subject arg along. But I'm not sure what to do about the "https://www.googleapis.com/auth/userinfo.email" scope (don't add it if subject is provided vs. try to add it but don't insist vs. document the need for it).

jennybc commented 1 year ago

I'm doing the most critical thing, which is to add subject as an argument to drive_auth(). The docs now also explicitly call out the need for the service account to have the "userinfo.email" scope. This may not be where the story ultimately ends, but this is definitely progress.