diff --git a/java/google/registry/proxy/ProxyConfig.java b/java/google/registry/proxy/ProxyConfig.java index 8cff2eeb3..46c07292e 100644 --- a/java/google/registry/proxy/ProxyConfig.java +++ b/java/google/registry/proxy/ProxyConfig.java @@ -37,7 +37,7 @@ public class ProxyConfig { public String projectId; public List gcpScopes; - public int accessTokenValidPeriodSeconds; + public int accessTokenRefreshBeforeExpirationSeconds; public int serverCertificateCacheSeconds; public Gcs gcs; public Kms kms; diff --git a/java/google/registry/proxy/ProxyModule.java b/java/google/registry/proxy/ProxyModule.java index 3ce06161a..c859ce2c8 100644 --- a/java/google/registry/proxy/ProxyModule.java +++ b/java/google/registry/proxy/ProxyModule.java @@ -15,9 +15,7 @@ package google.registry.proxy; import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Suppliers.memoizeWithExpiration; import static google.registry.proxy.ProxyConfig.getProxyConfig; -import static java.util.concurrent.TimeUnit.SECONDS; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; @@ -229,17 +227,19 @@ public class ProxyModule { @Named("accessToken") static Supplier provideAccessTokenSupplier( GoogleCredential credential, ProxyConfig config) { - return memoizeWithExpiration( - () -> { - try { - credential.refreshToken(); - } catch (IOException e) { - throw new RuntimeException("Cannot refresh access token.", e); - } - return credential.getAccessToken(); - }, - config.accessTokenValidPeriodSeconds, - SECONDS); + return () -> { + // If we never obtained an access token, the expiration time is null. + if (credential.getExpiresInSeconds() == null + // If we have an access token, make sure to refresh it ahead of time. + || credential.getExpiresInSeconds() < config.accessTokenRefreshBeforeExpirationSeconds) { + try { + credential.refreshToken(); + } catch (IOException e) { + throw new RuntimeException("Cannot refresh access token.", e); + } + } + return credential.getAccessToken(); + }; } @Singleton diff --git a/java/google/registry/proxy/config/default-config.yaml b/java/google/registry/proxy/config/default-config.yaml index f3659c136..d9de770da 100644 --- a/java/google/registry/proxy/config/default-config.yaml +++ b/java/google/registry/proxy/config/default-config.yaml @@ -20,7 +20,7 @@ gcpScopes: # to authenticate. - https://www.googleapis.com/auth/userinfo.email -# Access token is cached for 15 minutes. +# Refresh the access token 5 minutes before it expires. # # Depending on how the credential is obtained, its renewal behavior is # different. A credential backed by a private key (like the ADC obtained @@ -30,12 +30,14 @@ gcpScopes: # this, I got this number by logging in a GCE VM, calling curl on the metatdata # server every minute, and check the expiration time of the response). Calling # refreshToken() does *not* get a new token. The token is only refreshed by -# metadata server itself (every 3599 - 1699 = 1900 seconds). We cache the token -# for 900 seconds, which should be good for both cases. The private key -# generated token is in theory valid for 1h, and the token obtained from the -# metadata token is at least valid for 1699 seconds, so we can know for sure -# that during the period that it is cached, the token will not expire. -accessTokenValidPeriodSeconds: 900 +# metadata server itself (every 3599 - 1699 = 1900 seconds). +# +# We refresh the token 5 minutes before it expires, which should work in both +# cases. This is better than caching the token for a pre-defined period, because +# even right after #refreshToken() is called on the client side, tokens obtained +# from GCE metadata server may not be valid for the entirety of 3599 seconds. + +accessTokenRefreshBeforeExpirationSeconds: 300 # Server certificate is cached for 30 minutes. #