Open jennybc opened 5 years ago
From test fixtures in googleapis/google-auth-library-nodejs (among a gazillion other places), here's what the ADC JSON should look like for user creds:
{
"client_id": "client123",
"client_secret": "clientSecret123",
"refresh_token": "refreshToken123",
"type": "authorized_user"
}
This is (sort of) documented here but @craigcitro tells me this is deprecated:
https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login
I came across this recently with respect to authentication on Jupyter notebooks. An example here.
Its only needed in the context of when you need user authentication e.g. Google Analytics vs general services like BigQuery where the default gce_credentials()
are sufficient. I think its basically because the latter tokens are only scoped to /cloud
, and you can't use the GCE auth for other scopes.
Question: how does one even end up with an OAuth2 token stored as this sort of JSON? I'm thinking maybe via the gcloud cli?
I was recommended to use the gcloud auth application login
command to generate a token - but perhaps this is going soon if deprecated?
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
I then copy paste that token given into a httr Token create function:
gar_gce_auth_default <- function(access_token,
scopes){
json_creds <- jsonlite::fromJSON('~/.config/gcloud/application_default_credentials.json')
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)
}
The whole thing could be smoother, and I wonder if its necessary if you can generate the access token via other means, as its seems gcloud auth application-default login
is exactly the same as an OOB flow done via normal httr
.
On osx I haven't been able to make gargle work with application default credentials. Python and golang libraries work but for whatever reason I get back a null from gargle.
I ran into the same issue as @brokenjacobs on mac. It turned out that I was using a authorized_user
account and I had not specified the scope correctly/it was not one of the four valid_scopes
allowed by credentials_app_default()
I've not given much attention to application default credentials for this first release. I've used it successfully now (with a service account token), but I've got a few lingering questions and ideas for future refinement/extended support.
Also, parking notes and links here.
from https://www.jhanley.com/google-cloud-application-default-credentials
That does not fully capture all the locations checked by
gargle::credentials_app_default()
, but that is the first place it checks.Official ADC docs: https://cloud.google.com/docs/authentication/production and https://cloud.google.com/sdk/docs/
I put in some minimal docs for
gargle::credentials_app_default()
via 4256749d345da60ecd96e0c442c2c472fc3064cb.credentials_app_default()
looks for a file at a path encapsulated bycredentials_app_default_path()
. Here's where it looks, in order, where ALL_CAPS indicates env var:If a file exists at the path returned by
credentials_app_default_path()
, we parse it as JSON.It is assumed that it (via
info$type
) declares itself to be an OAuth or service account token.If it's OAuth, there's a bit of fiddling with scopes, then a new
httr::Token2.0
is instantiated "by hand".gcloud
cli?Question: should I just leave
credentials_app_default()
as is? Possible tweaks:init_oauth2.0 ()
instead ofhttr::Token2.0$new()
? This seems to be a preferred workflow and yet I don't think it's possible, because we want to shove an existing refresh token in there.gargle::Gargle2.0
subclass ofhttr::Token2.0
relevant?If this is a service account token, we call
credentials_service_account()
and then we're done.