diff --git a/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/identity_providers/ProviderBaseAdvancedSettingsPage.ts b/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/identity_providers/ProviderBaseAdvancedSettingsPage.ts
index e8395c0383..b328af5bf9 100644
--- a/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/identity_providers/ProviderBaseAdvancedSettingsPage.ts
+++ b/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/identity_providers/ProviderBaseAdvancedSettingsPage.ts
@@ -55,6 +55,7 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
private scopesInput = "#scopes";
private storeTokensSwitch = "#storeTokens";
private storedTokensReadable = "#storedTokensReadable";
+ private isAccessTokenJWT = "#isAccessTokenJWT";
private acceptsPromptNoneForwardFromClientSwitch = "#acceptsPromptNone";
private advancedSettingsToggle = ".pf-c-expandable-section__toggle";
private passLoginHintSwitch = "#passLoginHint";
@@ -112,6 +113,11 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
return this;
}
+ public clickIsAccessTokenJWTSwitch() {
+ cy.get(this.isAccessTokenJWT).parent().click();
+ return this;
+ }
+
public clickAcceptsPromptNoneForwardFromClientSwitch() {
cy.get(this.acceptsPromptNoneForwardFromClientSwitch).parent().click();
return this;
@@ -219,6 +225,11 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
return this;
}
+ public assertIsAccessTokenJWTTurnedOn(isOn: boolean) {
+ super.assertSwitchStateOn(cy.get(this.isAccessTokenJWT).parent(), isOn);
+ return this;
+ }
+
public assertAcceptsPromptNoneForwardFromClientSwitchTurnedOn(isOn: boolean) {
super.assertSwitchStateOn(
cy.get(this.acceptsPromptNoneForwardFromClientSwitch).parent(),
@@ -394,6 +405,8 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
this.assertStoreTokensSwitchTurnedOn(true);
this.clickStoredTokensReadableSwitch();
this.assertStoredTokensReadableTurnedOn(true);
+ this.clickIsAccessTokenJWTSwitch();
+ this.assertIsAccessTokenJWTTurnedOn(true);
this.clickTrustEmailSwitch();
this.assertTrustEmailSwitchTurnedOn(true);
this.clickAccountLinkingOnlySwitch();
@@ -406,8 +419,10 @@ export default class ProviderBaseGeneralSettingsPage extends PageObject {
this.selectSyncModeOption(SyncModeOption.legacy);
this.clickRevertBtn();
+ cy.get(this.advancedSettingsToggle).scrollIntoView().click();
this.assertStoreTokensSwitchTurnedOn(false);
this.assertStoredTokensReadableTurnedOn(false);
+ this.assertIsAccessTokenJWTTurnedOn(false);
this.assertTrustEmailSwitchTurnedOn(false);
this.assertAccountLinkingOnlySwitchTurnedOn(false);
this.assertHideOnLoginPageSwitchTurnedOn(false);
diff --git a/js/apps/admin-ui/public/locales/en/identity-providers-help.json b/js/apps/admin-ui/public/locales/en/identity-providers-help.json
index ec5007677c..225b444fd1 100644
--- a/js/apps/admin-ui/public/locales/en/identity-providers-help.json
+++ b/js/apps/admin-ui/public/locales/en/identity-providers-help.json
@@ -15,6 +15,7 @@
"logoutUrl": "End session endpoint to use to logout user from external IDP.",
"backchannelLogout": "Does the external IDP support backchannel logout?",
"disableUserInfo": "Disable usage of User Info service to obtain additional user information? Default is to use this OIDC service.",
+ "isAccessTokenJWT": "The Access Token received from the Identity Provider is a JWT and its claims will be accessible for mappers.",
"userInfoUrl": "The User Info Url. This is optional.",
"issuer": "The issuer identifier for the issuer of the response. If not provided, no validation will be performed.",
"scopes": "The scopes to be sent when asking for authorization. It can be a space-separated list of scopes. Defaults to 'openid'.",
diff --git a/js/apps/admin-ui/public/locales/en/identity-providers.json b/js/apps/admin-ui/public/locales/en/identity-providers.json
index 5977d3882a..5839772d57 100644
--- a/js/apps/admin-ui/public/locales/en/identity-providers.json
+++ b/js/apps/admin-ui/public/locales/en/identity-providers.json
@@ -99,6 +99,7 @@
"logoutUrl": "Logout URL",
"backchannelLogout": "Backchannel logout",
"disableUserInfo": "Disable user info",
+ "isAccessTokenJWT": "Access Token is JWT",
"userInfoUrl": "User Info URL",
"issuer": "Issuer",
"scopes": "Scopes",
diff --git a/js/apps/admin-ui/src/identity-providers/add/AdvancedSettings.tsx b/js/apps/admin-ui/src/identity-providers/add/AdvancedSettings.tsx
index 9dce00dc48..a7c55d40dd 100644
--- a/js/apps/admin-ui/src/identity-providers/add/AdvancedSettings.tsx
+++ b/js/apps/admin-ui/src/identity-providers/add/AdvancedSettings.tsx
@@ -132,6 +132,9 @@ export const AdvancedSettings = ({ isOIDC, isSAML }: AdvancedSettingsProps) => {
>
)}
+ {isOIDC && (
+
+ )}
params) {
String requestedIssuer = params.getFirst(OAuth2Constants.SUBJECT_ISSUER);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcAccessTokenOnlyClaimsUserAttributeMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcAccessTokenOnlyClaimsUserAttributeMapperTest.java
new file mode 100644
index 0000000000..aa36a4c0b6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcAccessTokenOnlyClaimsUserAttributeMapperTest.java
@@ -0,0 +1,29 @@
+package org.keycloak.testsuite.broker;
+
+import java.util.List;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+
+public class KcOidcAccessTokenOnlyClaimsUserAttributeMapperTest extends OidcUserAttributeMapperTest {
+
+ @Override
+ protected BrokerConfiguration getBrokerConfiguration() {
+ return new KcOidcBrokerConfiguration() {
+ @Override
+ public List createProviderClients() {
+ List clientsRepList = super.createProviderClients();
+ clientsRepList.stream()
+ .flatMap(clientRepresentation -> clientRepresentation.getProtocolMappers().stream())
+ .map(ProtocolMapperRepresentation::getConfig)
+ .forEach(protocolMapperConfig -> {
+ protocolMapperConfig.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
+ protocolMapperConfig.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "false");
+ protocolMapperConfig.put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, "false");
+ });
+
+ return clientsRepList;
+ }
+ };
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java
index 7d19eacdc8..59ea3a5d43 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerConfiguration.java
@@ -73,10 +73,10 @@ public class KcOidcBrokerConfiguration implements BrokerConfiguration {
client.setSecret(CLIENT_SECRET);
client.setRedirectUris(Collections.singletonList(getConsumerRoot() +
- "/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint/*"));
+ "/auth/realms/" + REALM_CONS_NAME + "/broker/" + getIDPAlias() + "/endpoint/*"));
client.setAdminUrl(getConsumerRoot() +
- "/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint");
+ "/auth/realms/" + REALM_CONS_NAME + "/broker/" + getIDPAlias() + "/endpoint");
OIDCAdvancedConfigWrapper.fromClientRepresentation(client).setPostLogoutRedirectUris(Collections.singletonList("+"));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcAccessTokenOnlyClaimsUserAttributeMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcAccessTokenOnlyClaimsUserAttributeMapperTest.java
new file mode 100644
index 0000000000..02111ee62e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcAccessTokenOnlyClaimsUserAttributeMapperTest.java
@@ -0,0 +1,57 @@
+package org.keycloak.testsuite.broker;
+
+import static org.keycloak.testsuite.broker.BrokerTestTools.createIdentityProvider;
+
+import java.util.List;
+import java.util.Map;
+import org.keycloak.broker.oidc.OIDCIdentityProviderConfig;
+import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
+import org.keycloak.models.IdentityProviderSyncMode;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+
+public class OidcAccessTokenOnlyClaimsUserAttributeMapperTest extends OidcUserAttributeMapperTest {
+
+ @Override
+ protected BrokerConfiguration getBrokerConfiguration() {
+ return new KcOidcBrokerConfiguration() {
+
+ private static final String OIDC_IDP_ALIAS = "oidc-idp";
+
+ @Override
+ public IdentityProviderRepresentation setUpIdentityProvider(
+ IdentityProviderSyncMode syncMode) {
+ final IdentityProviderRepresentation idp = createIdentityProvider(OIDC_IDP_ALIAS,
+ OIDCIdentityProviderFactory.PROVIDER_ID);
+
+ final Map config = idp.getConfig();
+ applyDefaultConfiguration(config, syncMode);
+ config.put(OIDCIdentityProviderConfig.IS_ACCESS_TOKEN_JWT, "true");
+
+ return idp;
+ }
+
+ @Override
+ public String getIDPAlias() {
+ return OIDC_IDP_ALIAS;
+ }
+
+ @Override
+ public List createProviderClients() {
+ List clientsRepList = super.createProviderClients();
+ clientsRepList.stream()
+ .flatMap(clientRepresentation -> clientRepresentation.getProtocolMappers().stream())
+ .map(ProtocolMapperRepresentation::getConfig)
+ .forEach(protocolMapperConfig -> {
+ protocolMapperConfig.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
+ protocolMapperConfig.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "false");
+ protocolMapperConfig.put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, "false");
+ });
+
+ return clientsRepList;
+ }
+ };
+ }
+}