diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java index dd2e9435a0081..63cac12d78d68 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java @@ -374,8 +374,8 @@ public enum Strategy { /** * Requires that the tokens are encrypted before being stored in the cookies. */ - @ConfigItem(defaultValueDocumentation = "false") - public Optional encryptionRequired = Optional.empty(); + @ConfigItem(defaultValue = "true") + public boolean encryptionRequired = true; /** * Secret which will be used to encrypt the tokens. @@ -385,12 +385,12 @@ public enum Strategy { @ConfigItem public Optional encryptionSecret = Optional.empty(); - public Optional isEncryptionRequired() { + public boolean isEncryptionRequired() { return encryptionRequired; } public void setEncryptionRequired(boolean encryptionRequired) { - this.encryptionRequired = Optional.of(encryptionRequired); + this.encryptionRequired = encryptionRequired; } public Optional getEncryptionSecret() { diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java index 0dde01e5b97c2..1a4592bf8dd99 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java @@ -287,10 +287,7 @@ public Uni apply(SecurityIdentity identity) { if (isBackChannelLogoutPendingAndValid(configContext, identity) || isFrontChannelLogoutValid(context, configContext, identity)) { - return OidcUtils - .removeSessionCookie(context, configContext.oidcConfig, - sessionCookie.getName(), - resolver.getTokenStateManager()) + return removeSessionCookie(context, configContext.oidcConfig) .map(new Function() { @Override public Void apply(Void t) { @@ -742,7 +739,9 @@ public Throwable apply(Throwable tInner) { LOG.debugf("Starting the final redirect"); return tInner; } - LOG.errorf("ID token verification has failed: %s", tInner.getMessage()); + String message = tInner.getCause() != null ? tInner.getCause().getMessage() + : tInner.getMessage(); + LOG.errorf("ID token verification has failed: %s", message); return new AuthenticationCompletionException(tInner); } }); diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTokenStateManager.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTokenStateManager.java index 0b8bc172cc2bb..01c622f4bab36 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTokenStateManager.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTokenStateManager.java @@ -129,7 +129,7 @@ private static String getRefreshTokenCookieName(OidcTenantConfig oidcConfig) { } private String encryptToken(String token, RoutingContext context, OidcTenantConfig oidcConfig) { - if (oidcConfig.tokenStateManager.encryptionRequired.orElse(false)) { + if (oidcConfig.tokenStateManager.encryptionRequired) { TenantConfigContext configContext = context.get(TenantConfigContext.class.getName()); try { return OidcUtils.encryptString(token, configContext.getTokenEncSecretKey()); @@ -141,7 +141,7 @@ private String encryptToken(String token, RoutingContext context, OidcTenantConf } private String decryptToken(String token, RoutingContext context, OidcTenantConfig oidcConfig) { - if (oidcConfig.tokenStateManager.encryptionRequired.orElse(false)) { + if (oidcConfig.tokenStateManager.encryptionRequired) { TenantConfigContext configContext = context.get(TenantConfigContext.class.getName()); try { return OidcUtils.decryptString(token, configContext.getTokenEncSecretKey()); diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java index a9b245bf4e1da..1141e45b6418f 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcUtils.java @@ -455,7 +455,7 @@ public static String encryptJson(JsonObject json, SecretKey key) throws Exceptio public static String encryptString(String jweString, SecretKey key) throws Exception { JsonWebEncryption jwe = new JsonWebEncryption(); - jwe.setAlgorithmHeaderValue(KeyEncryptionAlgorithm.A256KW.getAlgorithm()); + jwe.setAlgorithmHeaderValue(KeyEncryptionAlgorithm.A256GCMKW.getAlgorithm()); jwe.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithm.A256GCM.getAlgorithm()); jwe.setKey(key); jwe.setPlaintext(jweString); @@ -467,7 +467,7 @@ public static JsonObject decryptJson(String jweString, Key key) throws Exception } public static String decryptString(String jweString, Key key) throws Exception { - return decryptString(jweString, key, KeyEncryptionAlgorithm.A256KW); + return decryptString(jweString, key, KeyEncryptionAlgorithm.A256GCMKW); } public static String decryptString(String jweString, Key key, KeyEncryptionAlgorithm algorithm) throws JoseException { diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantConfigContext.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantConfigContext.java index 4e1e2190307a0..674320d38ebf0 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantConfigContext.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/TenantConfigContext.java @@ -1,12 +1,20 @@ package io.quarkus.oidc.runtime; +import java.nio.charset.StandardCharsets; + +import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.jboss.logging.Logger; +import io.quarkus.oidc.OIDCException; import io.quarkus.oidc.OidcTenantConfig; import io.quarkus.oidc.common.runtime.OidcCommonUtils; import io.smallrye.jwt.util.KeyUtils; public class TenantConfigContext { + private static final Logger LOG = Logger.getLogger(TenantConfigContext.class); /** * OIDC Provider @@ -39,8 +47,8 @@ public TenantConfigContext(OidcProvider client, OidcTenantConfig config, boolean this.oidcConfig = config; this.ready = ready; - pkceSecretKey = createPkceSecretKey(config); - tokenEncSecretKey = createTokenEncSecretKey(config); + pkceSecretKey = provider != null && provider.client != null ? createPkceSecretKey(config) : null; + tokenEncSecretKey = provider != null && provider.client != null ? createTokenEncSecretKey(config) : null; } private static SecretKey createPkceSecretKey(OidcTenantConfig config) { @@ -59,16 +67,24 @@ private static SecretKey createPkceSecretKey(OidcTenantConfig config) { } private static SecretKey createTokenEncSecretKey(OidcTenantConfig config) { - if (config.tokenStateManager.encryptionRequired.orElse(false)) { + if (config.tokenStateManager.encryptionRequired) { String encSecret = config.tokenStateManager.encryptionSecret .orElse(OidcCommonUtils.clientSecret(config.credentials)); - if (encSecret == null) { - throw new RuntimeException("Secret key for encrypting tokens is missing"); - } - if (encSecret.length() != 32) { - throw new RuntimeException("Secret key for encrypting tokens must be 32 characters long"); + try { + if (encSecret == null) { + LOG.warn("Secret key for encrypting tokens is missing, auto-generating it"); + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(256); + return keyGenerator.generateKey(); + } + byte[] secretBytes = encSecret.getBytes(StandardCharsets.UTF_8); + if (secretBytes.length < 32) { + LOG.warn("Secret key for encrypting tokens should be 32 characters long"); + } + return new SecretKeySpec(OidcUtils.getSha256Digest(secretBytes), "AES"); + } catch (Exception ex) { + throw new OIDCException(ex); } - return KeyUtils.createSecretKeyFromSecret(encSecret); } return null; } diff --git a/integration-tests/oidc-code-flow/src/main/resources/application.properties b/integration-tests/oidc-code-flow/src/main/resources/application.properties index e6f10e50207a9..2df9b465b5a00 100644 --- a/integration-tests/oidc-code-flow/src/main/resources/application.properties +++ b/integration-tests/oidc-code-flow/src/main/resources/application.properties @@ -10,6 +10,7 @@ quarkus.oidc.authentication.cookie-domain=localhost quarkus.oidc.authentication.extra-params.max-age=60 quarkus.oidc.application-type=web-app quarkus.oidc.authentication.cookie-suffix=test +quarkus.oidc.token-state-manager.encryption-required=false # OIDC client configuration quarkus.oidc-client.auth-server-url=${quarkus.oidc.auth-server-url} @@ -145,7 +146,6 @@ quarkus.oidc.tenant-split-tokens.auth-server-url=${quarkus.oidc.auth-server-url} quarkus.oidc.tenant-split-tokens.client-id=quarkus-app quarkus.oidc.tenant-split-tokens.credentials.secret=secret quarkus.oidc.tenant-split-tokens.token-state-manager.split-tokens=true -quarkus.oidc.tenant-split-tokens.token-state-manager.encryption-required=true quarkus.oidc.tenant-split-tokens.token-state-manager.encryption-secret=eUk1p7UB3nFiXZGUXi0uph1Y9p34YhBU quarkus.oidc.tenant-split-tokens.application-type=web-app diff --git a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java index a67cd4eb3f94e..43eb3ff67f284 100644 --- a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java +++ b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/CodeFlowTest.java @@ -17,6 +17,9 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + import org.hamcrest.Matchers; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -275,7 +278,15 @@ public void testCodeFlowForceHttpsRedirectUriWithQueryAndPkce() throws Exception Cookie sessionCookie = getSessionCookie(webClient, "tenant-https_test"); assertNotNull(sessionCookie); - JsonObject idToken = OidcUtils.decodeJwtContent(sessionCookie.getValue().split("\\|")[0]); + + String encryptedIdToken = sessionCookie.getValue().split("\\|")[0]; + + SecretKey key = new SecretKeySpec(OidcUtils + .getSha256Digest("secret".getBytes(StandardCharsets.UTF_8)), + "AES"); + String encodedIdToken = OidcUtils.decryptString(encryptedIdToken, key); + + JsonObject idToken = OidcUtils.decodeJwtContent(encodedIdToken); String expiresAt = idToken.getInteger("exp").toString(); page = webClient.getPage(endpointLocationWithoutQueryUri.toURL()); String response = page.getBody().asNormalizedText(); @@ -850,7 +861,7 @@ public void testDefaultSessionManagerIdTokenOnly() throws IOException, Interrupt assertEquals("tenant-idtoken-only:no refresh", page.getBody().asNormalizedText()); Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-idtoken-only"); - checkSingleTokenCookie(idTokenCookie, "ID"); + checkSingleTokenCookie(idTokenCookie, "ID", "secret"); assertNull(getSessionAtCookie(webClient, "tenant-idtoken-only")); assertNull(getSessionRtCookie(webClient, "tenant-idtoken-only")); @@ -860,7 +871,7 @@ public void testDefaultSessionManagerIdTokenOnly() throws IOException, Interrupt } @Test - public void testDefaultSessionManagerIdRefreshTokens() throws IOException, InterruptedException { + public void testDefaultSessionManagerIdRefreshTokens() throws Exception { try (final WebClient webClient = createWebClient()) { HtmlPage page = webClient.getPage("http://localhost:8081/web-app/tenant-id-refresh-token"); assertNotNull(getStateCookie(webClient, "tenant-id-refresh-token")); @@ -881,11 +892,16 @@ public void testDefaultSessionManagerIdRefreshTokens() throws IOException, Inter assertEquals("tenant-id-refresh-token:RT injected", page.getBody().asNormalizedText()); Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-id-refresh-token"); + + SecretKey key = new SecretKeySpec(OidcUtils + .getSha256Digest("secret".getBytes(StandardCharsets.UTF_8)), + "AES"); + String[] parts = idTokenCookie.getValue().split("\\|"); assertEquals(3, parts.length); - assertEquals("ID", OidcUtils.decodeJwtContent(parts[0]).getString("typ")); + assertEquals("ID", OidcUtils.decodeJwtContent(OidcUtils.decryptString(parts[0], key)).getString("typ")); assertEquals("", parts[1]); - assertEquals("Refresh", OidcUtils.decodeJwtContent(parts[2]).getString("typ")); + assertEquals("Refresh", OidcUtils.decodeJwtContent(OidcUtils.decryptString(parts[2], key)).getString("typ")); assertNull(getSessionAtCookie(webClient, "tenant-id-refresh-token")); assertNull(getSessionRtCookie(webClient, "tenant-id-refresh-token")); @@ -916,14 +932,15 @@ public void testDefaultSessionManagerSplitTokens() throws IOException, Interrupt page = webClient.getPage("http://localhost:8081/web-app/refresh/tenant-split-tokens"); assertEquals("tenant-split-tokens:RT injected", page.getBody().asNormalizedText()); + final String decryptSecret = "eUk1p7UB3nFiXZGUXi0uph1Y9p34YhBU"; Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-split-tokens"); - checkSingleTokenCookie(idTokenCookie, "ID", true); + checkSingleTokenCookie(idTokenCookie, "ID", decryptSecret); Cookie atTokenCookie = getSessionAtCookie(page.getWebClient(), "tenant-split-tokens"); - checkSingleTokenCookie(atTokenCookie, "Bearer", true); + checkSingleTokenCookie(atTokenCookie, "Bearer", decryptSecret); Cookie rtTokenCookie = getSessionRtCookie(page.getWebClient(), "tenant-split-tokens"); - checkSingleTokenCookie(rtTokenCookie, "Refresh", true); + checkSingleTokenCookie(rtTokenCookie, "Refresh", decryptSecret); // verify all the cookies are cleared after the session timeout webClient.getOptions().setRedirectEnabled(false); @@ -972,12 +989,12 @@ public void testDefaultSessionManagerIdRefreshSplitTokens() throws IOException, assertEquals("tenant-split-id-refresh-token:RT injected", page.getBody().asNormalizedText()); Cookie idTokenCookie = getSessionCookie(page.getWebClient(), "tenant-split-id-refresh-token"); - checkSingleTokenCookie(idTokenCookie, "ID"); + checkSingleTokenCookie(idTokenCookie, "ID", "secret"); assertNull(getSessionAtCookie(page.getWebClient(), "tenant-split-id-refresh-token")); Cookie rtTokenCookie = getSessionRtCookie(page.getWebClient(), "tenant-split-id-refresh-token"); - checkSingleTokenCookie(rtTokenCookie, "Refresh"); + checkSingleTokenCookie(rtTokenCookie, "Refresh", "secret"); // verify all the cookies are cleared after the session timeout webClient.getOptions().setRedirectEnabled(false); @@ -1005,26 +1022,30 @@ public Boolean call() throws Exception { } private void checkSingleTokenCookie(Cookie tokenCookie, String type) { - checkSingleTokenCookie(tokenCookie, type, false); + checkSingleTokenCookie(tokenCookie, type, null); } - private void checkSingleTokenCookie(Cookie tokenCookie, String type, boolean decrypt) { + private void checkSingleTokenCookie(Cookie tokenCookie, String type, String decryptSecret) { String[] cookieParts = tokenCookie.getValue().split("\\|"); assertEquals(1, cookieParts.length); String token = cookieParts[0]; String[] tokenParts = token.split("\\."); - if (decrypt) { + if (decryptSecret != null) { assertEquals(5, tokenParts.length); try { - token = OidcUtils.decryptString(token, KeyUtils.createSecretKeyFromSecret("eUk1p7UB3nFiXZGUXi0uph1Y9p34YhBU")); + SecretKey key = new SecretKeySpec(OidcUtils + .getSha256Digest(decryptSecret.getBytes(StandardCharsets.UTF_8)), + "AES"); + token = OidcUtils.decryptString(token, key); tokenParts = token.split("\\."); } catch (Exception ex) { fail("Token decryption has failed"); } } assertEquals(3, tokenParts.length); - assertEquals(type, OidcUtils.decodeJwtContent(token).getString("typ")); + JsonObject json = OidcUtils.decodeJwtContent(token); + assertEquals(type, json.getString("typ")); } @Test diff --git a/integration-tests/oidc-tenancy/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java b/integration-tests/oidc-tenancy/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java index 5c8ce5297d4df..219738a57ebd3 100644 --- a/integration-tests/oidc-tenancy/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java +++ b/integration-tests/oidc-tenancy/src/main/java/io/quarkus/it/keycloak/CustomTenantConfigResolver.java @@ -139,6 +139,7 @@ public OidcTenantConfig get() { config.setJwksPath(jwksUri); config.getToken().setIssuer("any"); config.tokenStateManager.setSplitTokens(true); + config.tokenStateManager.setEncryptionRequired(false); config.getAuthentication().setSessionAgeExtension(Duration.ofMinutes(1)); config.getAuthentication().setIdTokenRequired(false); return config; diff --git a/integration-tests/oidc-wiremock/src/main/resources/application.properties b/integration-tests/oidc-wiremock/src/main/resources/application.properties index cd675540342b3..c318ee68b82ac 100644 --- a/integration-tests/oidc-wiremock/src/main/resources/application.properties +++ b/integration-tests/oidc-wiremock/src/main/resources/application.properties @@ -36,7 +36,7 @@ quarkus.oidc.code-flow-encrypted-id-token-pem.token.decryption-key-location=priv quarkus.oidc.code-flow-form-post.auth-server-url=${keycloak.url}/realms/quarkus-form-post/ quarkus.oidc.code-flow-form-post.client-id=quarkus-web-app -quarkus.oidc.code-flow-form-post.credentials.secret=secret +quarkus.oidc.code-flow-form-post.credentials.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow quarkus.oidc.code-flow-form-post.application-type=web-app quarkus.oidc.code-flow-form-post.authentication.response-mode=form_post quarkus.oidc.code-flow-form-post.discovery-enabled=false diff --git a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java index d3273facb0eb8..57d95610e7d36 100644 --- a/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java +++ b/integration-tests/oidc-wiremock/src/test/java/io/quarkus/it/keycloak/CodeFlowAuthorizationTest.java @@ -13,8 +13,12 @@ import java.io.IOException; import java.net.URI; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.Set; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -154,7 +158,7 @@ public void testCodeFlowFormPostAndBackChannelLogout() throws IOException { } @Test - public void testCodeFlowFormPostAndFrontChannelLogout() throws IOException { + public void testCodeFlowFormPostAndFrontChannelLogout() throws Exception { defineCodeFlowLogoutStub(); try (final WebClient webClient = createWebClient()) { webClient.getOptions().setRedirectEnabled(true); @@ -174,9 +178,7 @@ public void testCodeFlowFormPostAndFrontChannelLogout() throws IOException { assertEquals("alice", page.getBody().asNormalizedText()); // Session is still active - Cookie sessionCookie = getSessionCookie(webClient, "code-flow-form-post"); - assertNotNull(sessionCookie); - JsonObject idTokenClaims = OidcUtils.decodeJwtContent(sessionCookie.getValue().split("\\|")[0]); + JsonObject idTokenClaims = decryptIdToken(webClient, "code-flow-form-post"); webClient.getOptions().setRedirectEnabled(false); @@ -238,7 +240,7 @@ public void testCodeFlowTokenIntrospection() throws Exception { } } - private void doTestCodeFlowUserInfo(String tenantId, long internalIdTokenLifetime) throws IOException { + private void doTestCodeFlowUserInfo(String tenantId, long internalIdTokenLifetime) throws Exception { try (final WebClient webClient = createWebClient()) { webClient.getOptions().setRedirectEnabled(true); HtmlPage page = webClient.getPage("http://localhost:8081/" + tenantId); @@ -251,9 +253,7 @@ private void doTestCodeFlowUserInfo(String tenantId, long internalIdTokenLifetim assertEquals("alice:alice:alice, cache size: 1", page.getBody().asNormalizedText()); - Cookie sessionCookie = getSessionCookie(webClient, tenantId); - assertNotNull(sessionCookie); - JsonObject idTokenClaims = OidcUtils.decodeJwtContent(sessionCookie.getValue().split("\\|")[0]); + JsonObject idTokenClaims = decryptIdToken(webClient, tenantId); assertNull(idTokenClaims.getJsonObject(OidcUtils.USER_INFO_ATTRIBUTE)); long issuedAt = idTokenClaims.getLong("iat"); long expiresAt = idTokenClaims.getLong("exp"); @@ -263,6 +263,19 @@ private void doTestCodeFlowUserInfo(String tenantId, long internalIdTokenLifetim } } + private JsonObject decryptIdToken(WebClient webClient, String tenantId) throws Exception { + Cookie sessionCookie = getSessionCookie(webClient, tenantId); + assertNotNull(sessionCookie); + String encryptedIdToken = sessionCookie.getValue().split("\\|")[0]; + + SecretKey key = new SecretKeySpec(OidcUtils + .getSha256Digest("AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" + .getBytes(StandardCharsets.UTF_8)), + "AES"); + String encodedIdToken = OidcUtils.decryptString(encryptedIdToken, key); + return OidcUtils.decodeJwtContent(encodedIdToken); + } + private void doTestCodeFlowUserInfoCashedInIdToken() throws Exception { try (final WebClient webClient = createWebClient()) { webClient.getOptions().setRedirectEnabled(true); @@ -276,9 +289,7 @@ private void doTestCodeFlowUserInfoCashedInIdToken() throws Exception { assertEquals("alice:alice:alice, cache size: 0", page.getBody().asNormalizedText()); - Cookie sessionCookie = getSessionCookie(webClient, "code-flow-user-info-github-cached-in-idtoken"); - assertNotNull(sessionCookie); - JsonObject idTokenClaims = OidcUtils.decodeJwtContent(sessionCookie.getValue().split("\\|")[0]); + JsonObject idTokenClaims = decryptIdToken(webClient, "code-flow-user-info-github-cached-in-idtoken"); assertNotNull(idTokenClaims.getJsonObject(OidcUtils.USER_INFO_ATTRIBUTE)); // refresh