public CacheState getCacheState() {
   if (exception != null) {
     return CacheState.Exception;
   }
   long now = clock.currentTimeMillis();
   if (staleTimeMs == null || now < staleTimeMs) {
     return CacheState.Good;
   } else if (now < expiresTimeMs) {
     return CacheState.Stale;
   } else {
     return CacheState.Expired;
   }
 }
 /**
  * Verifies that the given ID token is valid using the cached public keys.
  *
  * <p>It verifies:
  *
  * <ul>
  *   <li>The issuer is {@link #getIssuer()} by calling {@link IdToken#verifyIssuer(String)}.
  *   <li>The audience is one of {@link #getAudience()} by calling {@link
  *       IdToken#verifyAudience(Collection)}.
  *   <li>The current time against the issued at and expiration time, using the {@link #getClock()}
  *       and allowing for a time skew specified in {#link {@link #getAcceptableTimeSkewSeconds()}
  *       , by calling {@link IdToken#verifyTime(long, long)}.
  * </ul>
  *
  * <p>Overriding is allowed, but it must call the super implementation.
  *
  * @param idToken ID token
  * @return {@code true} if verified successfully or {@code false} if failed
  */
 public boolean verify(IdToken idToken) {
   return (issuer == null || idToken.verifyIssuer(issuer))
       && (audience == null || idToken.verifyAudience(audience))
       && idToken.verifyTime(clock.currentTimeMillis(), acceptableTimeSkewSeconds);
 }