googleapis / google-auth-library-java

Open source Auth client library for Java
https://developers.google.com/identity
BSD 3-Clause "New" or "Revised" License
405 stars 218 forks source link

ComputeEngineCredentials.createScoped copies existing AccessToken #1387

Open erlendnils1 opened 2 months ago

erlendnils1 commented 2 months ago

After upgrading com.google.oauth-client from v1.21.0 to 1.23.0 we started getting 403 ACCESS_TOKEN_SCOPE_INSUFFICIENT errors from the PlayIntegrity.decodeIntegrityToken service. This was the case until the initial AccessToken expired after which it started working again.

We obtained the credentials used (through a HttpCredentialsAdapter) to access the PlayIntegrity service in this way:

var scopedCredentials = GoogleCredentials.getApplicationDefault().createScoped(PlayIntegrityScopes.all());

The cause of the changed behavior appears to be from this commit: https://github.com/googleapis/google-auth-library-java/commit/7e268611d2c2152e84702b1c67ca846902bbe2d5 which changes the ComputeEngineCredentials.createScope implementation to copy a lot more state from the original ComputeEngineCredentials object to the new, scoped ComputeEngineCredentials object. This includes copying the AccessToken from the original, which does not seem like the desired behaviour when the scopes are updated.

We have added an immediate refresh after creating the scoped credentials to make sure we get a new access token with the correct scope. This has solved the issue for us, but I assume this may be a gotcha that affects more users.

Workaround:

var scopedCredentials = GoogleCredentials.getApplicationDefault().createScoped(PlayIntegrityScopes.all());
scopedCredentials.refresh();
roma2341 commented 2 weeks ago

In google-auth-library-oauth2-http 1.19.0 i also got ACCESS_TOKEN_SCOPE_INSUFFICIENT randomly, I will try to use your fix and update library to latest version. What is interesting is that delegatedCredential.getAccessToken() gave me null just after credential creation. But sometimes it returns an AccessToken object. is It ok ? How about calling refreshIfExpired() ? Will it help ?

zhumin8 commented 1 week ago

In google-auth-library-oauth2-http 1.19.0 i also got ACCESS_TOKEN_SCOPE_INSUFFICIENT randomly, I will try to use your fix and update library to latest version. What is interesting is that delegatedCredential.getAccessToken() gave me null just after credential creation. But sometimes it returns an AccessToken object. is It ok ? How about calling refreshIfExpired() ? Will it help ?

Did the workaround above worked for your case? and do you mind clarifying what credential class you are using for delegatedCredential you mentioned above, is it also ComputeEngineCredentials?

roma2341 commented 18 hours ago

In google-auth-library-oauth2-http 1.19.0 i also got ACCESS_TOKEN_SCOPE_INSUFFICIENT randomly, I will try to use your fix and update library to latest version. What is interesting is that delegatedCredential.getAccessToken() gave me null just after credential creation. But sometimes it returns an AccessToken object. is It ok ? How about calling refreshIfExpired() ? Will it help ?

Did the workaround above worked for your case? and do you mind clarifying what credential class you are using for delegatedCredential you mentioned above, is it also ComputeEngineCredentials?

Yes , my issue was resolved after I added .refresh()

I had something like:

var delegatedCredentials = adminCredential
                .createDelegated(email)
                .createScoped(GOOGLE_AUTH_USER_SCOPES);

And I had ACCESS_TOKEN_SCOPE_INSUFFICIENT error frequently when uses these credentials But after I added these line errors now not reappear: delegatedCredential.refresh();

I still don't understand why I have to do it each time I create delegated credentials, I thought that google libraries code automatically refreshes tokens when necessary... this solution looks like a dirty hack.