diff --git a/core/src/main/java/org/keycloak/util/TokenUtil.java b/core/src/main/java/org/keycloak/util/TokenUtil.java index 92d7d13273..6b699afd58 100644 --- a/core/src/main/java/org/keycloak/util/TokenUtil.java +++ b/core/src/main/java/org/keycloak/util/TokenUtil.java @@ -46,6 +46,9 @@ public class TokenUtil { public static final String TOKEN_TYPE_JWT_ACCESS_TOKEN = "at+jwt"; public static final String TOKEN_TYPE_JWT_ACCESS_TOKEN_PREFIXED = "application/" + TOKEN_TYPE_JWT_ACCESS_TOKEN; + // https://openid.net/specs/openid-connect-backchannel-1_0.html#LogoutToken + public static final String TOKEN_TYPE_JWT_LOGOUT_TOKEN = "logout+jwt"; + public static final String TOKEN_TYPE_KEYCLOAK_ID = "Serialized-ID"; public static final String TOKEN_TYPE_ID = "ID"; diff --git a/services/src/main/java/org/keycloak/jose/jws/DefaultTokenManager.java b/services/src/main/java/org/keycloak/jose/jws/DefaultTokenManager.java index 4bd94b5b35..3775084824 100644 --- a/services/src/main/java/org/keycloak/jose/jws/DefaultTokenManager.java +++ b/services/src/main/java/org/keycloak/jose/jws/DefaultTokenManager.java @@ -78,7 +78,8 @@ public class DefaultTokenManager implements TokenManager { SignatureProvider signatureProvider = session.getProvider(SignatureProvider.class, signatureAlgorithm); SignatureSignerContext signer = signatureProvider.signer(); - String encodedToken = new JWSBuilder().type("JWT").jsonContent(token).sign(signer); + String type = type(token.getCategory()); + String encodedToken = new JWSBuilder().type(type).jsonContent(token).sign(signer); return encodedToken; } @@ -235,6 +236,15 @@ public class DefaultTokenManager implements TokenManager { return encodedToken; } + private String type(TokenCategory category) { + switch (category) { + case LOGOUT: + return TokenUtil.TOKEN_TYPE_JWT_LOGOUT_TOKEN; + default: + return "JWT"; + } + } + private boolean isTokenEncryptRequired(TokenCategory category) { if (cekManagementAlgorithm(category) == null) return false; if (encryptAlgorithm(category) == null) return false; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java index 46928a6971..fd53ec562c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java @@ -336,7 +336,12 @@ public class LogoutTest extends AbstractKeycloakTest { MatcherAssert.assertThat(response.getFirstHeader(HttpHeaders.LOCATION).getValue(), is(oauth.APP_AUTH_ROOT)); } - validateLogoutToken(testingClient.testApp().getBackChannelLogoutToken()); + String rawLogoutToken = testingClient.testApp().getBackChannelRawLogoutToken(); + JWSInput jwsInput = new JWSInput(rawLogoutToken); + LogoutToken logoutToken = jwsInput.readJsonContent(LogoutToken.class); + validateLogoutToken(logoutToken); + JWSHeader logoutTokenHeader = jwsInput.getHeader(); + assertEquals("logout+jwt", logoutTokenHeader.getType()); } finally { rep.getAttributes().put(OIDCConfigAttributes.BACKCHANNEL_LOGOUT_URL, ""); clientResource.update(rep);