diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
index 1014c0b..8984a4d 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
@@ -141,6 +141,15 @@ public class UserInfoEndpoint {
UserSessionModel userSession = session.sessions().getUserSession(realm, token.getSessionState());
ClientSessionModel clientSession = session.sessions().getClientSession(token.getClientSession());
+ if( userSession == null ) {
+ userSession = session.sessions().getOfflineUserSession(realm, token.getSessionState());
+ if( AuthenticationManager.isOfflineSessionValid(realm, userSession)) {
+ clientSession = session.sessions().getOfflineClientSession(realm, token.getClientSession());
+ } else {
+ userSession = null;
+ clientSession = null;
+ }
+ }
if (userSession == null) {
event.error(Errors.USER_SESSION_NOT_FOUND);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
index e6ec392..c57b64e 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -250,6 +250,24 @@ public class UserInfoTest extends AbstractKeycloakTest {
}
@Test
+ public void testSessionExpiredOfflineAccess() throws Exception {
+ Client client = ClientBuilder.newClient();
+
+ try {
+ AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client, true);
+
+ testingClient.testing().removeUserSessions("test");
+
+ Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken());
+
+ testSuccessfulUserInfoResponse(response);
+ response.close();
+ } finally {
+ client.close();
+ }
+ }
+
+ @Test
public void testUnsuccessfulUserInfoRequest() throws Exception {
Client client = ClientBuilder.newClient();
@@ -274,8 +292,12 @@ public class UserInfoTest extends AbstractKeycloakTest {
}
private AccessTokenResponse executeGrantAccessTokenRequest(Client client) {
+ return executeGrantAccessTokenRequest(client, false);
+ }
+
+ private AccessTokenResponse executeGrantAccessTokenRequest(Client client, boolean requestOfflineToken) {
UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
- URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
+ URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
String header = BasicAuthHelper.createHeader("test-app", "password");
@@ -283,6 +305,9 @@ public class UserInfoTest extends AbstractKeycloakTest {
form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
.param("username", "test-user@localhost")
.param("password", "password");
+ if( requestOfflineToken) {
+ form.param("scope", "offline_access");
+ }
Response response = grantTarget.request()
.header(HttpHeaders.AUTHORIZATION, header)