diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/TokenCallable.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/TokenCallable.java index b1c328020f..ffaa5926e2 100644 --- a/authz/client/src/main/java/org/keycloak/authorization/client/util/TokenCallable.java +++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/TokenCallable.java @@ -18,15 +18,19 @@ package org.keycloak.authorization.client.util; import java.util.concurrent.Callable; +import org.jboss.logging.Logger; import org.keycloak.authorization.client.Configuration; import org.keycloak.authorization.client.representation.ServerConfiguration; +import org.keycloak.common.util.Time; import org.keycloak.jose.jws.JWSInput; import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessTokenResponse; +import org.keycloak.representations.RefreshToken; import org.keycloak.util.JsonSerialization; public class TokenCallable implements Callable { + private static Logger log = Logger.getLogger(TokenCallable.class); private final String userName; private final String password; private final Http http; @@ -54,6 +58,22 @@ public class TokenCallable implements Callable { } else { clientToken = obtainAccessToken(userName, password); } + } else { + String refreshTokenValue = clientToken.getRefreshToken(); + try { + RefreshToken refreshToken = JsonSerialization.readValue(new JWSInput(refreshTokenValue).getContent(), RefreshToken.class); + if (!refreshToken.isActive() || !isTokenTimeToLiveSufficient(refreshToken)) { + log.debug("Refresh token is expired."); + if (userName == null || password == null) { + clientToken = obtainAccessToken(); + } else { + clientToken = obtainAccessToken(userName, password); + } + } + } catch (Exception e) { + clientToken = null; + throw new RuntimeException(e); + } } String token = clientToken.getToken(); @@ -61,8 +81,10 @@ public class TokenCallable implements Callable { try { AccessToken accessToken = JsonSerialization.readValue(new JWSInput(token).getContent(), AccessToken.class); - if (accessToken.isActive()) { + if (accessToken.isActive() && this.isTokenTimeToLiveSufficient(accessToken)) { return token; + } else { + log.debug("Access token is expired."); } clientToken = http.post(serverConfiguration.getTokenEndpoint()) @@ -81,6 +103,10 @@ public class TokenCallable implements Callable { return clientToken.getToken(); } + public boolean isTokenTimeToLiveSufficient(AccessToken token) { + return token != null && (token.getExpiration() - getConfiguration().getTokenMinimumTimeToLive()) > Time.currentTime(); + } + /** * Obtains an access token using the client credentials. *