Skip to content

Commit b4f791b

Browse files
graziangmposolda
authored andcommitted
Remove session_state from tokens
Closes #27624 Signed-off-by: Giuseppe Graziano <[email protected]>
1 parent 811c70d commit b4f791b

File tree

15 files changed

+153
-42
lines changed

15 files changed

+153
-42
lines changed

core/src/main/java/org/keycloak/representations/IDToken.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
package org.keycloak.representations;
1919

20-
import com.fasterxml.jackson.annotation.JsonAlias;
2120
import com.fasterxml.jackson.annotation.JsonIgnore;
2221
import com.fasterxml.jackson.annotation.JsonProperty;
2322
import org.keycloak.TokenCategory;
@@ -66,10 +65,8 @@ public class IDToken extends JsonWebToken {
6665

6766
protected Long auth_time;
6867

69-
// session_state is deprecated, sid should be used instead
70-
@JsonProperty(SESSION_STATE)
71-
@JsonAlias(SESSION_ID)
72-
protected String sessionState;
68+
@JsonProperty(SESSION_ID)
69+
protected String sessionId;
7370

7471
@JsonProperty(AT_HASH)
7572
protected String accessTokenHash;
@@ -177,17 +174,22 @@ public void setAuthTime(int authTime) {
177174
this.auth_time = Long.valueOf(authTime);
178175
}
179176

180-
@JsonProperty(SESSION_ID)
177+
181178
public String getSessionId() {
182-
return sessionState;
179+
return sessionId;
183180
}
184181

185-
public String getSessionState() {
186-
return sessionState;
182+
public void setSessionId(String sessionId) {
183+
this.sessionId = sessionId;
187184
}
188185

189-
public void setSessionState(String sessionState) {
190-
this.sessionState = sessionState;
186+
/**
187+
* @deprecated Use {@link #getSessionId()} instead.
188+
*/
189+
@Deprecated
190+
@JsonIgnore
191+
public String getSessionState() {
192+
return sessionId;
191193
}
192194

193195
public String getAccessTokenHash() {

core/src/main/java/org/keycloak/representations/RefreshToken.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public RefreshToken(AccessToken token) {
4343
this.issuer = token.issuer;
4444
this.subject = token.subject;
4545
this.issuedFor = token.issuedFor;
46-
this.sessionState = token.sessionState;
46+
this.sessionId = token.sessionId;
4747
this.nonce = token.nonce;
4848
this.audience = new String[] { token.issuer };
4949
this.scope = token.scope;

docs/documentation/server_admin/topics/clients/con-protocol-mappers.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Further, when the resource server acquires the PII removed from the access token
7575

7676
Information that cannot be removed from a lightweight access token::
7777
Protocol mappers can controls which information is put onto an access token and the lightweight access token use the protocol mappers. Therefore, the following information cannot be removed from the lightweight access. +
78-
`exp`, `iat`, `jti`, `iss`, `sub`, `typ`, `azp`, `nonce`, `session_state`, `sid`, `scope`, `cnf`
78+
`exp`, `iat`, `jti`, `iss`, `sub`, `typ`, `azp`, `nonce`, `sid`, `scope`, `cnf`
7979

8080
Using a lightweight access token in {project_name}::
8181
By applying `use-lightweight-access-token` executor of <<_client_policies, client policies>> to a client, the client can receive a lightweight access token instead of an access token. The lightweight access token contains a claim controlled by a protocol mapper where its setting `Add to lightweight access token`(default OFF) is turned ON. Also, by turning ON its setting `Add to token introspection` of the protocol mapper, the client can obtain the claim by sending the access token to {project_name}'s token introspection endpoint.

docs/documentation/upgrading/topics/changes/changes-25_0_0.adoc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,14 @@ This scope contains preconfigured protocol mappers for the following claims:
7777

7878
* `auth_time`
7979

80-
This helps to reduce even more the number of claims in a lightweight access token, but also gives the chance to configure claims that were always added automatically.
80+
This provides additional help to reduce the number of claims in a lightweight access token, but also gives the chance to configure claims that were always added automatically.
81+
82+
= Removed `session_state` claim
83+
84+
The `session_state` claim, which contains the same value as the `sid` claim, is now removed from all tokens as it is not required according to the OpenID Connect Front-Channel Logout and OpenID Connect Back-Channel Logout specifications. The `session_state` claim remains present in the Access Token Response in accordance with OpenID Connect Session Management specification.
85+
86+
Note that the `setSessionState()` method is also removed from the `IDToken` class in favor of the `setSessionId()` method, and the `getSessionState()` method is now deprecated.
87+
88+
A new `Session State (session_state)` mapper is also included and can be assigned to client scopes (for instance `basic` client scope) to revert to the old behavior.
89+
90+
If an old version of the JS adapter is used, the `Session State (session_state)` mapper should also be used via client scopes as described above.

js/apps/admin-ui/cypress/e2e/clients_test.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ describe("Clients test", () => {
301301

302302
clientDetailsPage.goToClientScopesEvaluateGeneratedUserInfoTab();
303303
cy.get("div#generatedIdToken").contains('"preferred_username": "admin"');
304-
cy.get("div#generatedIdToken").contains('"session_state"');
304+
cy.get("div#generatedIdToken").contains('"sid"');
305305
});
306306
});
307307

js/libs/keycloak-js/src/keycloak.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ function Keycloak (config) {
10091009
if (token) {
10101010
kc.token = token;
10111011
kc.tokenParsed = jwtDecode(token);
1012-
kc.sessionId = kc.tokenParsed.session_state;
1012+
kc.sessionId = kc.tokenParsed.sid;
10131013
kc.authenticated = true;
10141014
kc.subject = kc.tokenParsed.sub;
10151015
kc.realmAccess = kc.tokenParsed.realm_access;

services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import java.util.concurrent.atomic.AtomicBoolean;
3333
import java.util.concurrent.atomic.AtomicInteger;
3434
import java.util.function.BiFunction;
35-
import java.util.function.Predicate;
3635
import java.util.stream.Collectors;
3736

3837
import jakarta.ws.rs.HttpMethod;
@@ -366,7 +365,7 @@ private AuthorizationResponse createAuthorizationResponse(KeycloakIdentity ident
366365

367366
if (accessToken.getSessionState() == null) {
368367
// Skip generating refresh token for accessToken without sessionState claim. This is "stateless" accessToken not pointing to any real persistent userSession
369-
rpt.setSessionState(null);
368+
rpt.setSessionId(null);
370369
} else {
371370
if (OIDCAdvancedConfigWrapper.fromClientModel(client).isUseRefreshToken()) {
372371
responseBuilder.generateRefreshToken();

services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ private AccessToken getAccessTokenFromStoredData(AccessToken token, UserSessionM
164164
newToken.issuer(token.getIssuer());
165165
newToken.setNonce(token.getNonce());
166166
newToken.setScope(token.getScope());
167-
newToken.setSessionState(token.getSessionState());
167+
newToken.setSessionId(token.getSessionId());
168168

169169
// In the case of a refresh token, aud is a basic claim.
170170
newToken.audience(token.getAudience());

services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,7 @@ protected AccessToken initToken(RealmModel realm, ClientModel client, UserModel
991991
token.setAcr(acr);
992992
}
993993

994-
token.setSessionState(session.getId());
994+
token.setSessionId(session.getId());
995995
ClientScopeModel offlineAccessScope = KeycloakModelUtils.getClientScopeByName(realm, OAuth2Constants.OFFLINE_ACCESS);
996996
boolean offlineTokenRequested = offlineAccessScope == null ? false
997997
: clientSessionCtx.getClientScopeIds().contains(offlineAccessScope.getId());
@@ -1190,7 +1190,7 @@ public AccessTokenResponseBuilder generateIDToken(boolean isIdTokenAsDetachedSig
11901190
idToken.issuedFor(accessToken.getIssuedFor());
11911191
idToken.issuer(accessToken.getIssuer());
11921192
idToken.setNonce(clientSessionCtx.getAttribute(OIDCLoginProtocol.NONCE_PARAM, String.class));
1193-
idToken.setSessionState(accessToken.getSessionState());
1193+
idToken.setSessionId(accessToken.getSessionId());
11941194
idToken.expiration(accessToken.getExpiration());
11951195

11961196
// Protocol mapper is supposed to set this in case "step_up_authentication" feature enabled

services/src/main/java/org/keycloak/protocol/oidc/grants/ClientCredentialsGrantType.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.keycloak.events.Errors;
3030
import org.keycloak.events.EventType;
3131
import org.keycloak.models.ClientSessionContext;
32-
import org.keycloak.models.KeycloakSession;
3332
import org.keycloak.models.UserModel;
3433
import org.keycloak.models.UserSessionModel;
3534
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@@ -142,7 +141,7 @@ public Response process(Context context) {
142141
if (useRefreshToken) {
143142
responseBuilder = responseBuilder.generateRefreshToken();
144143
} else {
145-
responseBuilder.getAccessToken().setSessionState(null);
144+
responseBuilder.getAccessToken().setSessionId(null);
146145
}
147146

148147
checkAndBindMtlsHoKToken(responseBuilder, useRefreshToken);

0 commit comments

Comments
 (0)