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 5e1e247..4cedd6b 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -214,16 +214,22 @@ public class TokenManager {
}
UserSessionModel userSession = session.sessions().getUserSession(realm, token.getSessionState());
- if (!AuthenticationManager.isSessionValid(realm, userSession)) {
- return false;
+ if (AuthenticationManager.isSessionValid(realm, userSession)) {
+ ClientSessionModel clientSession = session.sessions().getClientSession(realm, token.getClientSession());
+ if (clientSession != null) {
+ return true;
+ }
}
- ClientSessionModel clientSession = session.sessions().getClientSession(realm, token.getClientSession());
- if (clientSession == null) {
- return false;
+ userSession = session.sessions().getOfflineUserSession(realm, token.getSessionState());
+ if (AuthenticationManager.isOfflineSessionValid(realm, userSession)) {
+ ClientSessionModel clientSession = session.sessions().getOfflineClientSession(realm, token.getClientSession());
+ if (clientSession != null) {
+ return true;
+ }
}
- return true;
+ return false;
}
public RefreshResult refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel authorizedClient, String encodedRefreshToken, EventBuilder event, HttpHeaders headers) throws OAuthErrorException {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
index ee700dc..114b70e 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
@@ -237,6 +237,38 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest {
assertNull(rep.getSubject());
}
+ // KEYCLOAK-4829
+ @Test
+ public void testIntrospectAccessTokenOfflineAccess() throws Exception {
+ oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
+ oauth.doLogin("test-user@localhost", "password");
+ String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+ AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
+
+ setTimeOffset(86400);
+
+ // "Online" session still exists, but is invalid
+ accessTokenResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken(), "password");
+ String tokenResponse = oauth.introspectAccessTokenWithClientCredential("confidential-cli", "secret1", accessTokenResponse.getAccessToken());
+ TokenMetadataRepresentation rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
+
+ assertTrue(rep.isActive());
+ assertEquals("test-user@localhost", rep.getUserName());
+ assertEquals("test-app", rep.getClientId());
+
+ // "Online" session doesn't even exists
+ testingClient.testing().removeExpired("test");
+
+ accessTokenResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken(), "password");
+ tokenResponse = oauth.introspectAccessTokenWithClientCredential("confidential-cli", "secret1", accessTokenResponse.getAccessToken());
+ rep = JsonSerialization.readValue(tokenResponse, TokenMetadataRepresentation.class);
+
+ assertTrue(rep.isActive());
+ assertEquals("test-user@localhost", rep.getUserName());
+ assertEquals("test-app", rep.getClientId());
+ }
+
+
@Test
public void testIntrospectAccessTokenUserDisabled() throws Exception {
oauth.doLogin("test-user@localhost", "password");