diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index b6e1050..a7ba496 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -315,7 +315,7 @@ public class TokenEndpoint {
String redirectUriParam = formParams.getFirst(OAuth2Constants.REDIRECT_URI);
// KEYCLOAK-4478 Backwards compatibility with the adapters earlier than KC 3.4.2
- if (redirectUriParam != null && redirectUriParam.contains("session_state=")) {
+ if (redirectUriParam != null && redirectUriParam.contains("session_state=") && !redirectUri.contains("session_state=")) {
redirectUriParam = KeycloakUriBuilder.fromUri(redirectUriParam)
.replaceQueryParam(OAuth2Constants.SESSION_STATE, null)
.build().toString();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/AbstractOIDCResponseTypeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/AbstractOIDCResponseTypeTest.java
index 1794359..1a097de 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/AbstractOIDCResponseTypeTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/AbstractOIDCResponseTypeTest.java
@@ -91,6 +91,21 @@ public abstract class AbstractOIDCResponseTypeTest extends AbstractTestRealmKeyc
@Test
+ public void initialSessionStateUsedInRedirect() {
+ EventRepresentation loginEvent = loginUserWithRedirect("abcdef123456", OAuthClient.APP_ROOT + "/auth?session_state=foo");
+
+ OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, isFragment());
+ Assert.assertNotNull(authzResponse.getSessionState());
+
+ List<IDToken> idTokens = testAuthzResponseAndRetrieveIDTokens(authzResponse, loginEvent);
+
+ for (IDToken idToken : idTokens) {
+ Assert.assertEquals(authzResponse.getSessionState(), idToken.getSessionState());
+ }
+ }
+
+
+ @Test
public void authorizationRequestMissingResponseType() throws IOException {
oauth.responseType(null);
UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
@@ -174,6 +189,24 @@ public abstract class AbstractOIDCResponseTypeTest extends AbstractTestRealmKeyc
return events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
}
+ protected EventRepresentation loginUserWithRedirect(String nonce, String redirectUri) {
+ if (nonce != null) {
+ oauth.nonce(nonce);
+ }
+
+ if (redirectUri != null) {
+ oauth.redirectUri(redirectUri);
+ }
+
+ driver.navigate().to(oauth.getLoginFormUrl());
+
+ loginPage.assertCurrent();
+ loginPage.login("test-user@localhost", "password");
+ Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+ return events.expectLogin().detail(Details.REDIRECT_URI, redirectUri).detail(Details.USERNAME, "test-user@localhost").assertEvent();
+ }
+
protected abstract boolean isFragment();
protected abstract List<IDToken> testAuthzResponseAndRetrieveIDTokens(OAuthClient.AuthorizationEndpointResponse authzResponse, EventRepresentation loginEvent);