google-auth-library-java icon indicating copy to clipboard operation
google-auth-library-java copied to clipboard

How to set a timeout for GoogleCredentials?

Open hiranya911 opened this issue 6 years ago • 7 comments

GoogleCredentials can be initialized with an optional HttpTransportFactory. But this doesn't provide any means of setting the connection and read timeout for the HTTP requests made by the credentials implementation. Is there a way to set these timeout values for GoogleCredentials?

More context: In the Google HTTP client, the recommended way to set timeouts is via an HttpRequestInitializer that gets passed into the HttpRequestFactory.

myTransport.createRequestFactory(new HttpRequestInitializer() {
      @Override
      public void initialize(HttpRequest request) throws IOException {
        request.setConnectTimeout(10000);
        request.setReadTimeout(10000);
      }
    });

But currently there appears to be no way to specify a request initializer for GoogleCredentials. As a result, there's no simple way to configure the timeouts for the HTTP requests made by this implementation.

This is a somewhat critical issue, since GoogleCredentials get invoked before any other HTTP requests are made by the client. The default timeout settings of GoogleCredentials essentially mask and override any timeout values set in the client.

myTransport.createRequestFactory(new HttpRequestInitializer() {
      @Override
      public void initialize(HttpRequest request) throws IOException {
        credentials.initialize(request);
        request.setConnectTimeout(10000);
        request.setReadTimeout(10000);
      }
    });

In the above example you expect requests to timeout after 10 seconds. But because credentials are in the initializer chain, it won't timeout until 60s (the default).

hiranya911 avatar Oct 08 '19 17:10 hiranya911

There's also some retry logic baked into the flow that is not configurable:

https://github.com/googleapis/google-auth-library-java/blob/f4f05be44ab073ee16d92a1647e74b8bb187a442/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java#L404-L425

By default failing requests are retried up to 10 times with exponential backoff.

hiranya911 avatar Oct 08 '19 18:10 hiranya911

I agree, there does not seem to be a easy way to do this today. Is your use case you would like to fail faster in your code? Although it is not ideal, I bet you could add timeouts in by wrapping GoogleCredentials as not a lot seems to be final.

codyoss avatar Oct 15 '19 14:10 codyoss

Yes, fail fast would be one use case.

Although it is not ideal, I bet you could add timeouts in by wrapping GoogleCredentials as not a lot seems to be final.

Does that imply implementing some sort of a timer around the GoogleCredentials.refreshAccessToken() API?

It appears there's no easy way to implement actual connection/socket timeouts since HTTP request logic is essentially buried in the GoogleCredentials.refreshAccessToken() method. Couple of solutions I can think of:

  1. Make it possible to pass an HttpRequestInitializer into GoogleCredentials.
  2. Expose an initializeTokenRequest(HttpRequest req) method from GoogleCredentials that users can override. Default implementation will do nothing.

hiranya911 avatar Oct 15 '19 21:10 hiranya911

Does that imply implementing some sort of a timer around the GoogleCredentials.refreshAccessToken() API?

That method needs to be implemented, its default impl from the base class is to throw an exception. Are you using GoogleCredentials directly or one of the other classes that implement it?

I will bring those possible solutions up with my team. Thank you for your input!

codyoss avatar Oct 15 '19 21:10 codyoss

Ours is also a developer product: https://github.com/firebase/firebase-admin-java

Developers pass GoogleCredentials instances to our SDK. I believe most developers would use one of the factory methods to create credentials -- GoogleCredentials.fromStream(...). The actual instance they get is something like ServiceAccountCredentials or ApplicationDefaultCredentials.

It would be great if there was an API to wrap an existing GoogleCredentials instance with a timeout. This way our SDK can "inject" a timeout to the object passed in by the developer:

GoogleCredentials copy = credentials.withTimeout(connectTimeout, readTimeout);

// Or more generally
GoogleCredentials copy = credentials.withHttpRequestInitializer(initializer);

But we can also settle for a solution that would require developers to initialize GoogleCredentials with a timeout or a request initializer.

hiranya911 avatar Oct 15 '19 23:10 hiranya911

@hiranya911 @yoshi-automation Is there an update on this?

anmol1vw13 avatar Sep 14 '22 05:09 anmol1vw13

https://github.com/googleapis/google-auth-library-java/pull/1053

please check merge request

stager0909 avatar Oct 13 '22 07:10 stager0909