Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement fetchIdToken on UserRefreshClient #876

Closed
amammay opened this issue Jan 21, 2020 · 10 comments · Fixed by #1811
Closed

Implement fetchIdToken on UserRefreshClient #876

amammay opened this issue Jan 21, 2020 · 10 comments · Fixed by #1811
Assignees
Labels
priority: p3 Desirable enhancement or fix. May not be included in next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@amammay
Copy link

amammay commented Jan 21, 2020

Thanks for stopping by to let us know something could be better!

PLEASE READ: If you have a support contract with Google, please create an issue in the support console instead of filing on GitHub. This will ensure a timely response.

Is your feature request related to a problem? Please describe.
Implement the fetchIdToken method on the user refresh client, currently can not provide the UserRefreshClient as a provider to the IdTokenClient.
Describe the solution you'd like
I believe the solution would be as simple as adding the method to the UserRefreshClient, and then making sure the following payload would be sent to get an identity token.

Example

curl --verbose \
      --data client_id=OTHER_CLIENT_ID \
      --data client_secret=OTHER_CLIENT_SECRET \
      --data refresh_token=REFRESH_TOKEN \
      --data grant_type=refresh_token \
      --data audience=IAP_CLIENT_ID \
      https://oauth2.googleapis.com/token

Describe alternatives you've considered
Currently just am using this library up until i need to exchange my refresh token for an identity token. When i retrieve a valid refresh token, i then call my own method to do the exchange of refresh token -> identity token. With a custom audience set.
Additional context
I was following this guide, https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_a_desktop_app when i came across the short coming.

I am willing to make the pull request in the next couple of days to fix the issue if that works for the maintainers?

@yoshi-automation yoshi-automation added the triage me I really want to be triaged. label Jan 21, 2020
@JustinBeckwith JustinBeckwith added the type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. label Jan 22, 2020
@yoshi-automation yoshi-automation removed the triage me I really want to be triaged. label Jan 22, 2020
@bcoe
Copy link
Contributor

bcoe commented Jan 24, 2020

@bshaffer mind chiming in here, you'd mentioned there were reasons this method didn't exist on the UserRefreshClient I believe?

@bshaffer
Copy link
Contributor

bshaffer commented Jan 24, 2020

Hello @amammay !
There are a few caviats to your example. Specifically, the OTHER_CLIENT_ID and IAP_CLIENT_ID have to be in the same project, otherwise the OAuth2 server responds with the following error:

{
  "error": "invalid_audience",
  "error_description": "The audience client and the client need to be in the same project."
}

This rules out the ability to use the default User Credentials we get when we run gcloud init, which is one of the main value propositions of this feature. Without it, you'd still be able to use this functionality, but it requires the following steps:

  1. Authenticate using an OAuth Client you create (in the same project as your IAP client). This requires a 3-legged flow, where the user will be redirected back to your web or asked to enter an authorization somewhere, similar to how gcloud init works.
  2. Make sure your authorization request includes the email scope, otherwise your refresh token request will not include an ID token with the email claim.
  3. Make sure your authorization request includes access_type=offline and prompt=consent, otherwise you will not receive a refresh_token with the response.
  4. Retrieve the resulting access token, grab the refresh_token, and pass it to UserRefreshClient along with your client credentials (and set audience if different from the client credentials).
  5. The resulting ID token will be able to access IAP resources.

The advantage here is an end user could authorize you to make repeated calls to your IAP resource for them. Is this a use-case you have? I am happy to add support if so, but otherwise it's best to stick with service accounts and the JWT client.

@amammay
Copy link
Author

amammay commented Jan 26, 2020

@bshaffer thanks for the info! I ended up learning more about the steps through trial and error over the past couple days as well and my flow is pretty spot on with what you described. We have focused our gcp environment to be mainly based around user auth over service account auth for day to day activities. I think a really good example is the following.

I’m hosting a private npm registry on app engine standard protected with iap, i ended up creating a wrapper cli around npm to go through the oauth flow, and cache the refresh token to the users machine, and then for subsequent calls, exchange the refresh token for the identity token. That way we can have a nice audit trail of all our users that have accessed our private resources on app engine since since we would be going against their accounts instead of a service accounts.(use case could would be people that have configured their projects for elevated levels of Iam auditing policies)

I defiantly see from your point of view how this is pretty unique to calls that reside in the same project, and I know for my individual use case this would be awesome, but not sure how much use this would be for others.

@bshaffer
Copy link
Contributor

@amammay That does sound like a valid use case!

I'm still concerned that the steps outlined are so awkward that a user will receive the above The audience client and the client need to be in the same project error, become frustrated, and ultimately fail to achieve what they're after.

We could mitigate this by throwing an error if we see the gcloud client ID being used to fetch an ID token using UserRefresh. E.g. "An ID Token cannot be fetched with User Credentials from gcloud, and instead must be authorized using the same client ID as the IAP Protected Resource. You may want to use a service account instead."

@WaldoJeffers
Copy link

Any news on this one? As mentioned in #1543, when trying to get an OpenID token locally, it's a bit surprising to find that google-auth-library is unable to handle what seems to be a fairly simple use case.

The only workaround I've found is to use the RPC HTTP API to get a token, which in my use case, almost makes google-auth-library useless :(

@danielbankhead
Copy link
Contributor

@WaldoJeffers I'll find some time to work on this feature shortly. I personally want this functionality as well, but haven't had much time in recent months.

@WaldoJeffers
Copy link

@danielbankhead Thank you, let me know if I can be of any help

@tareksaleem
Copy link

I am sorry if these words will be annoying. about 2 years the library team ignoring the issue and say there is no issue and close other opened tickets as duplicates instead of focusing on investigating it and resolving. It's a very simple use case to use my application default credentials as a user to generate an id token, don't know why something like this is not supported, it's already there in the CLI so why it doesn't exist in the SDK? Is it something very challenging to do?

@RyanStack
Copy link

@danielbankhead thank you for putting this on your radar. This would be a big help for us as well.

@danielbankhead
Copy link
Contributor

Thanks for your patience, the following PR will close out this feature request:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: p3 Desirable enhancement or fix. May not be included in next release. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants