keycloak-aplcache

Details

diff --git a/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java b/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java
index 109c35c..fd8ec0f 100755
--- a/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java
+++ b/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java
@@ -15,6 +15,9 @@ public class AccessTokenResponse {
     @JsonProperty("expires_in")
     protected long expiresIn;
 
+    @JsonProperty("refresh_expires_in")
+    protected long refreshExpiresIn;
+
     @JsonProperty("refresh_token")
     protected String refreshToken;
 
@@ -46,6 +49,14 @@ public class AccessTokenResponse {
         this.expiresIn = expiresIn;
     }
 
+    public long getRefreshExpiresIn() {
+        return refreshExpiresIn;
+    }
+
+    public void setRefreshExpiresIn(long refreshExpiresIn) {
+        this.refreshExpiresIn = refreshExpiresIn;
+    }
+
     public String getRefreshToken() {
         return refreshToken;
     }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 7297f31..219f1a1 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -413,6 +413,9 @@ public class TokenManager {
             if (refreshToken != null) {
                 String encodedToken = new JWSBuilder().jsonContent(refreshToken).rsa256(realm.getPrivateKey());
                 res.setRefreshToken(encodedToken);
+                if (refreshToken.getExpiration() != 0) {
+                    res.setRefreshExpiresIn(refreshToken.getExpiration() - Time.currentTime());
+                }
             }
             int notBefore = realm.getNotBefore();
             if (client.getNotBefore() > notBefore) notBefore = client.getNotBefore();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index 27c2e51..f0e2339 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -102,6 +102,7 @@ public class AccessTokenTest {
         Assert.assertEquals(200, response.getStatusCode());
 
         Assert.assertThat(response.getExpiresIn(), allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(300)));
+        Assert.assertThat(response.getRefreshExpiresIn(), allOf(greaterThanOrEqualTo(1750), lessThanOrEqualTo(1800)));
 
         Assert.assertEquals("bearer", response.getTokenType());
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
index 5fd7ad7..1625338 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -403,6 +403,7 @@ public class OAuthClient {
         private String accessToken;
         private String tokenType;
         private int expiresIn;
+        private int refreshExpiresIn;
         private String refreshToken;
 
         private String error;
@@ -421,6 +422,7 @@ public class OAuthClient {
                 accessToken = responseJson.getString("access_token");
                 tokenType = responseJson.getString("token_type");
                 expiresIn = responseJson.getInt("expires_in");
+                refreshExpiresIn = responseJson.getInt("refresh_expires_in");
 
                 if (responseJson.has(OAuth2Constants.REFRESH_TOKEN)) {
                     refreshToken = responseJson.getString(OAuth2Constants.REFRESH_TOKEN);
@@ -447,6 +449,10 @@ public class OAuthClient {
             return expiresIn;
         }
 
+        public int getRefreshExpiresIn() {
+            return refreshExpiresIn;
+        }
+
         public int getStatusCode() {
             return statusCode;
         }