keycloak-aplcache

Merge pull request #1002 from pedroigor/master [KEYCLOAK-883]

2/27/2015 2:13:49 AM

Changes

Details

diff --git a/connections/jpa/src/main/resources/META-INF/persistence.xml b/connections/jpa/src/main/resources/META-INF/persistence.xml
index 8609f07..eff01c4 100755
--- a/connections/jpa/src/main/resources/META-INF/persistence.xml
+++ b/connections/jpa/src/main/resources/META-INF/persistence.xml
@@ -18,6 +18,7 @@
         <class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
         <class>org.keycloak.models.jpa.entities.ScopeMappingEntity</class>
         <class>org.keycloak.models.jpa.entities.IdentityProviderEntity</class>
+        <class>org.keycloak.models.jpa.entities.ClientIdentityProviderMappingEntity</class>
         <class>org.keycloak.models.jpa.entities.ClaimTypeEntity</class>
         <class>org.keycloak.models.jpa.entities.ProtocolMapperEntity</class>
 
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
index 6139c3d..b27e9bd 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
@@ -73,13 +73,14 @@
                 <constraints nullable="false"/>
             </column>
         </createTable>
-        <createTable tableName="CLIENT_ALLOWED_IDENTITY_PROVIDER">
+        <createTable tableName="CLIENT_IDENTITY_PROVIDER_MAPPING">
             <column name="CLIENT_ID" type="VARCHAR(36)">
                 <constraints nullable="false"/>
             </column>
-            <column name="INTERNAL_ID" type="VARCHAR(36)">
+            <column name="IDENTITY_PROVIDER_ID" type="VARCHAR(36)">
                 <constraints nullable="false"/>
             </column>
+            <column name="RETRIEVE_TOKEN" type="BOOLEAN(1)"/>
         </createTable>
         <createTable tableName="CLIENT_PROTOCOL_MAPPER">
             <column name="CLIENT_ID" type="VARCHAR(36)">
@@ -104,10 +105,11 @@
         <addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="FEDERATED_IDENTITY" constraintName="FK404288B92EF007A6" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
         <addForeignKeyConstraint baseColumnNames="IDENTITY_PROVIDER_ID" baseTableName="IDENTITY_PROVIDER_CONFIG" constraintName="FKDC4897CF864C4E43" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
         <addForeignKeyConstraint baseColumnNames="PROTOCOL_MAPPER_ID" baseTableName="PROTOCOL_MAPPER_CONFIG" constraintName="FK_PMConfig" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="ID" referencedTableName="PROTOCOL_MAPPER"/>
-        <addForeignKeyConstraint baseColumnNames="INTERNAL_ID" baseTableName="CLIENT_ALLOWED_IDENTITY_PROVIDER" constraintName="FK_7CELWNIBJI49AVXSRTUF6XJ12" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
-        <addUniqueConstraint columnNames="INTERNAL_ID,CLIENT_ID" constraintName="UK_7CAELWNIBJI49AVXSRTUF6XJ12" tableName="CLIENT_ALLOWED_IDENTITY_PROVIDER"/>
+        <addForeignKeyConstraint baseColumnNames="IDENTITY_PROVIDER_ID" baseTableName="CLIENT_IDENTITY_PROVIDER_MAPPING" constraintName="FK_7CELWNIBJI49AVXSRTUF6XJ12" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
+        <addForeignKeyConstraint baseColumnNames="CLIENT_ID" baseTableName="CLIENT_IDENTITY_PROVIDER_MAPPING" constraintName="FK_56ELWNIBJI49AVXSRTUF6XJ23" referencedColumnNames="ID" referencedTableName="CLIENT"/>
         <addForeignKeyConstraint baseColumnNames="MAPPING_ID" baseTableName="CLIENT_PROTOCOL_MAPPER" constraintName="FK_CPCM" referencedColumnNames="ID" referencedTableName="PROTOCOL_MAPPER"/>
         <addUniqueConstraint columnNames="CLIENT_ID,MAPPING_ID" constraintName="UK_CPCM" tableName="CLIENT_PROTOCOL_MAPPER"/>
         <addUniqueConstraint columnNames="PROVIDER_NONIMAL_ID" constraintName="UK_2DAELWNIBJI49AVXSRTUF6XJ33" tableName="IDENTITY_PROVIDER"/>
+        <addUniqueConstraint columnNames="IDENTITY_PROVIDER_ID,CLIENT_ID" constraintName="UK_7CAELWNIBJI49AVXSRTUF6XJ12" tableName="CLIENT_IDENTITY_PROVIDER_MAPPING"/>
     </changeSet>
 </databaseChangeLog>
diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
index 9ca74f0..6537fc2 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -2,7 +2,6 @@ package org.keycloak.representations.idm;
 
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -29,7 +28,7 @@ public class ApplicationRepresentation {
     protected Boolean fullScopeAllowed;
     protected Integer nodeReRegistrationTimeout;
     protected Map<String, Integer> registeredNodes;
-    protected List<String> allowedIdentityProviders;
+    protected List<ClientIdentityProviderMappingRepresentation> identityProviders;
     protected List<ClientProtocolMappingRepresentation> protocolMappers;
 
     public String getId() {
@@ -192,12 +191,12 @@ public class ApplicationRepresentation {
         this.frontchannelLogout = frontchannelLogout;
     }
 
-    public List<String> getAllowedIdentityProviders() {
-        return this.allowedIdentityProviders;
+    public List<ClientIdentityProviderMappingRepresentation> getIdentityProviders() {
+        return this.identityProviders;
     }
 
-    public void setAllowedIdentityProviders(List<String> allowedIdentityProviders) {
-        this.allowedIdentityProviders = allowedIdentityProviders;
+    public void setIdentityProviders(List<ClientIdentityProviderMappingRepresentation> identityProviders) {
+        this.identityProviders = identityProviders;
     }
 
     public List<ClientProtocolMappingRepresentation> getProtocolMappers() {
diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientIdentityProviderMappingRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientIdentityProviderMappingRepresentation.java
new file mode 100644
index 0000000..fdc02d3
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientIdentityProviderMappingRepresentation.java
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm;
+
+/**
+ * @author pedroigor
+ */
+public class ClientIdentityProviderMappingRepresentation {
+
+    protected String id;
+    protected boolean retrieveToken;
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String identityProviderId) {
+        this.id = identityProviderId;
+    }
+
+    public boolean isRetrieveToken() {
+        return this.retrieveToken;
+    }
+
+    public void setRetrieveToken(boolean retrieveToken) {
+        this.retrieveToken = retrieveToken;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
index aa095a7..c12a9eb 100755
--- a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
@@ -2,7 +2,6 @@ package org.keycloak.representations.idm;
 
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -23,8 +22,8 @@ public class OAuthClientRepresentation {
     protected Boolean directGrantsOnly;
     protected Boolean fullScopeAllowed;
     protected Boolean frontchannelLogout;
-    protected List<String> allowedIdentityProviders;
     protected List<ClientProtocolMappingRepresentation> protocolMappers;
+    private List<ClientIdentityProviderMappingRepresentation> identityProviders;
 
 
     public String getId() {
@@ -139,12 +138,12 @@ public class OAuthClientRepresentation {
         this.frontchannelLogout = frontchannelLogout;
     }
 
-    public List<String> getAllowedIdentityProviders() {
-        return this.allowedIdentityProviders;
+    public List<ClientIdentityProviderMappingRepresentation> getIdentityProviders() {
+        return this.identityProviders;
     }
 
-    public void setAllowedIdentityProviders(List<String> allowedIdentityProviders) {
-        this.allowedIdentityProviders = allowedIdentityProviders;
+    public void setIdentityProviders(List<ClientIdentityProviderMappingRepresentation> identityProviders) {
+        this.identityProviders = identityProviders;
     }
 
     public List<ClientProtocolMappingRepresentation> getProtocolMappers() {
diff --git a/docbook/reference/en/en-US/modules/identity-broker.xml b/docbook/reference/en/en-US/modules/identity-broker.xml
index 6ccc630..233afed 100755
--- a/docbook/reference/en/en-US/modules/identity-broker.xml
+++ b/docbook/reference/en/en-US/modules/identity-broker.xml
@@ -962,7 +962,7 @@ Authorization: Bearer {keycloak_access_token}]]></programlisting>
     </section>
 
     <section>
-        <title>Enabling/Disabling Identity Providers for Service Providers</title>
+        <title>Configuring Identity Providers for Applications</title>
         <para>
             By default, all identity providers enabled for a particular realm are also available to all its applications.
             However, you can also specify which identity providers should be available when
@@ -993,6 +993,10 @@ Authorization: Bearer {keycloak_access_token}]]></programlisting>
                 </para>
             </listitem>
         </orderedlist>
+        <para>
+            From this page you can also configure if an application is allowed to retrieve tokens from an specific identity provider. For that,
+            just click on the <emphasis>Can Retrieve Token</emphasis> button.
+        </para>
     </section>
 
     <section>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
index 617d5ab..3e758c2 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
@@ -43,75 +43,95 @@ module.controller('ApplicationCredentialsCtrl', function($scope, $location, real
     });
 });
 
-module.controller('ApplicationIdentityProviderCtrl', function($scope, $location, realm, application, Application, $location, Notifications) {
+module.controller('ApplicationIdentityProviderCtrl', function($scope, $location, $route, realm, application, Application, $location, Notifications) {
     $scope.realm = realm;
     $scope.application = angular.copy(application);
+    var length = 0;
 
-    $scope.identityProviders = [];
+    if ($scope.application.identityProviders) {
+        length = $scope.application.identityProviders.length;
+    } else {
+        $scope.application.identityProviders = new Array(realm.identityProviders.length);
+    }
 
-    if (!$scope.application.allowedIdentityProviders) {
-        $scope.application.allowedIdentityProviders = [];
+    for (j = length; j < realm.identityProviders.length; j++) {
+        $scope.application.identityProviders[j] = {};
     }
 
+    $scope.identityProviders = [];
+
     for (j = 0; j < realm.identityProviders.length; j++) {
         var identityProvider = realm.identityProviders[j];
         var match = false;
-
-        for (i = 0; i < $scope.application.allowedIdentityProviders.length; i++) {
-            var appProvider = $scope.application.allowedIdentityProviders[i];
-
-            if (appProvider == identityProvider.id) {
-                $scope.identityProviders[i] = identityProvider;
-                match = true;
+        var applicationProvider;
+
+        for (i = 0; i < $scope.application.identityProviders.length; i++) {
+            applicationProvider = $scope.application.identityProviders[i];
+
+            if (applicationProvider) {
+                if (applicationProvider.retrieveToken) {
+                    applicationProvider.retrieveToken = applicationProvider.retrieveToken.toString();
+                } else {
+                    applicationProvider.retrieveToken = false.toString();
+                }
+
+                if (applicationProvider.id == identityProvider.id) {
+                    $scope.identityProviders[i] = {};
+                    $scope.identityProviders[i].identityProvider = identityProvider;
+                    $scope.identityProviders[i].retrieveToken = applicationProvider.retrieveToken.toString();
+                    break;
+                }
+
+                applicationProvider = null;
             }
         }
 
-        if (!match) {
-            var length = $scope.identityProviders.length;
-
-            length = length + $scope.application.allowedIdentityProviders.length;
+        if (applicationProvider == null) {
+            var length = $scope.identityProviders.length + $scope.application.identityProviders.length;
 
-            $scope.identityProviders[length] = identityProvider;
+            $scope.identityProviders[length] = {};
+            $scope.identityProviders[length].identityProvider = identityProvider;
+            $scope.identityProviders[length].retrieveToken = false.toString();
         }
     }
 
     $scope.identityProviders = $scope.identityProviders.filter(function(n){ return n != undefined });
 
+    var oldCopy = angular.copy($scope.application);
+
     $scope.save = function() {
         var selectedProviders = [];
 
-        for (i = 0; i < $scope.application.allowedIdentityProviders.length; i++) {
-            var appProvider = $scope.application.allowedIdentityProviders[i];
+        for (i = 0; i < $scope.application.identityProviders.length; i++) {
+            var appProvider = $scope.application.identityProviders[i];
 
-            if (appProvider) {
+            if (appProvider.id != null && appProvider.id != false) {
                 selectedProviders[selectedProviders.length] = appProvider;
             }
         }
 
-        $scope.allowedIdentityProviders = $scope.application.allowedIdentityProviders;
-        $scope.application.allowedIdentityProviders = selectedProviders;
+        $scope.application.identityProviders = selectedProviders;
 
         Application.update({
             realm : realm.realm,
             application : application.id
         }, $scope.application, function() {
             $scope.changed = false;
-            $scope.application.allowedIdentityProviders = $scope.allowedIdentityProviders;
-            $location.url("/realms/" + realm.realm + "/applications/" + application.id + "/identity-provider");
+            $route.reload();
             Notifications.success("Your changes have been saved to the application.");
         });
     };
 
     $scope.reset = function() {
-        $scope.application = angular.copy(application);
+        $scope.application = angular.copy(oldCopy);
         $scope.changed = false;
     };
 
-    $scope.$watch(function() {
-        return $location.path();
-    }, function() {
-        $scope.path = $location.path().substring(1).split("/");
-    });
+    $scope.$watch('application', function() {
+        if (!angular.equals($scope.application, oldCopy)) {
+            $scope.changed = true;
+        }
+    }, true);
 });
 
 module.controller('ApplicationSamlKeyCtrl', function($scope, $location, $http, $upload, realm, application,
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
index dec42f5..1237f57 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
@@ -324,74 +324,94 @@ module.controller('OAuthClientRevocationCtrl', function($scope, realm, oauth, OA
     }
 });
 
-module.controller('OAuthClientIdentityProviderCtrl', function($scope, realm, oauth, OAuthClient, $location, Notifications) {
+module.controller('OAuthClientIdentityProviderCtrl', function($scope, $route, realm, oauth, OAuthClient, $location, Notifications) {
     $scope.realm = realm;
     $scope.oauth = angular.copy(oauth);
+    var length = 0;
 
-    $scope.identityProviders = [];
+    if ($scope.oauth.identityProviders) {
+        length = $scope.oauth.identityProviders.length;
+    } else {
+        $scope.oauth.identityProviders = new Array(realm.identityProviders.length);
+    }
 
-    if (!$scope.oauth.allowedIdentityProviders) {
-        $scope.oauth.allowedIdentityProviders = [];
+    for (j = length; j < realm.identityProviders.length; j++) {
+        $scope.oauth.identityProviders[j] = {};
     }
 
+    $scope.identityProviders = [];
+
     for (j = 0; j < realm.identityProviders.length; j++) {
         var identityProvider = realm.identityProviders[j];
         var match = false;
-
-        for (i = 0; i < $scope.oauth.allowedIdentityProviders.length; i++) {
-            var appProvider = $scope.oauth.allowedIdentityProviders[i];
-
-            if (appProvider == identityProvider.id) {
-                $scope.identityProviders[i] = identityProvider;
-                match = true;
+        var applicationProvider;
+
+        for (i = 0; i < $scope.oauth.identityProviders.length; i++) {
+            applicationProvider = $scope.oauth.identityProviders[i];
+
+            if (applicationProvider) {
+                if (applicationProvider.retrieveToken) {
+                    applicationProvider.retrieveToken = applicationProvider.retrieveToken.toString();
+                } else {
+                    applicationProvider.retrieveToken = false.toString();
+                }
+
+                if (applicationProvider.id == identityProvider.id) {
+                    $scope.identityProviders[i] = {};
+                    $scope.identityProviders[i].identityProvider = identityProvider;
+                    $scope.identityProviders[i].retrieveToken = applicationProvider.retrieveToken.toString();
+                    break;
+                }
+
+                applicationProvider = null;
             }
         }
 
-        if (!match) {
-            var length = $scope.identityProviders.length;
-
-            length = length + $scope.oauth.allowedIdentityProviders.length;
+        if (applicationProvider == null) {
+            var length = $scope.identityProviders.length + $scope.oauth.identityProviders.length;
 
-            $scope.identityProviders[length] = identityProvider;
+            $scope.identityProviders[length] = {};
+            $scope.identityProviders[length].identityProvider = identityProvider;
+            $scope.identityProviders[length].retrieveToken = false.toString();
         }
     }
 
     $scope.identityProviders = $scope.identityProviders.filter(function(n){ return n != undefined });
 
+    var oldCopy = angular.copy($scope.oauth);
+
     $scope.save = function() {
         var selectedProviders = [];
 
-        for (i = 0; i < $scope.oauth.allowedIdentityProviders.length; i++) {
-            var appProvider = $scope.oauth.allowedIdentityProviders[i];
+        for (i = 0; i < $scope.oauth.identityProviders.length; i++) {
+            var appProvider = $scope.oauth.identityProviders[i];
 
-            if (appProvider) {
+            if (appProvider.id != null && appProvider.id != false) {
                 selectedProviders[selectedProviders.length] = appProvider;
             }
         }
 
-        $scope.allowedIdentityProviders = $scope.oauth.allowedIdentityProviders;
-        $scope.oauth.allowedIdentityProviders = selectedProviders;
+        $scope.oauth.identityProviders = selectedProviders;
 
         OAuthClient.update({
             realm : realm.realm,
             oauth : oauth.id
         }, $scope.oauth, function() {
             $scope.changed = false;
-            $scope.oauth.allowedIdentityProviders = $scope.allowedIdentityProviders;
-            $location.url("/realms/" + realm.realm + "/oauth-clients/" + oauth.id + "/identity-provider");
+            $route.reload();
             Notifications.success("Your changes have been saved to the application.");
         });
     };
 
     $scope.reset = function() {
-        $scope.oauth = angular.copy(oauth);
+        $scope.oauth = angular.copy(oldCopy);
         $scope.changed = false;
     };
 
-    $scope.$watch(function() {
-        return $location.path();
-    }, function() {
-        $scope.path = $location.path().substring(1).split("/");
-    });
+    $scope.$watch('oauth', function() {
+        if (!angular.equals($scope.oauth, oldCopy)) {
+            $scope.changed = true;
+        }
+    }, true);
 });
 
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html
index 57adcd3..aeb3b8d 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-identity-provider.html
@@ -7,17 +7,24 @@
             <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Identity Provider</li>
         </ol>
-        <h2 data-ng-hide="create"><span>{{application.name}}</span> Identity Provider Settings<span tooltip-placement="right" tooltip="Select which identity providers can be used for this application. By default, all identity providers are enabled. Select one or more to restrict." class="fa fa-info-circle"></span></h2>
+        <h2 data-ng-hide="create"><span>{{application.name}}</span> Identity Provider Settings</h2>
         <form class="form-horizontal" name="identityProviderForm" novalidate>
             <div class="form-group" ng-repeat="identityProvider in identityProviders">
-                <legend><span class="text">{{identityProvider.name}}</span></legend>
-                <label class="col-sm-2 control-label" for="{{identityProvider.id}}">Enable</label>
+                <legend><span class="text">{{identityProvider.identityProvider.name}}</span></legend>
+                <label class="col-sm-2 control-label" for="{{identityProvider.identityProvider.id}}">Enable&nbsp;<span tooltip-placement="right" tooltip="If disabled, users can not login to the application using this identity provider." class="fa fa-info-circle"></span></label>
                 <div class="col-sm-4">
-                    <input ng-model="application.allowedIdentityProviders[$index]" name="identityProvider.id" id="identityProvider.id" value="identityProvider.id" onoffswitchmodel />
+                    <input ng-model="application.identityProviders[$index].id" name="identityProvider.identityProvider.id" id="identityProvider.identityProvider.id" value="identityProvider.identityProvider.id" onoffswitchmodel />
+                </div>
+                <div data-ng-show="application.identityProviders[$index].id">
+                    <label class="col-sm-2 control-label" for="{{identityProvider.identityProvider.id}}retrieveToken">Can Retrieve Token&nbsp;<span tooltip-placement="right" tooltip="If disabled, the application can not retrieve tokens from the identity provider." class="fa fa-info-circle"></span></label>
+                    <div class="col-sm-4">
+                        <input ng-model="application.identityProviders[$index].retrieveToken" name="identityProvider.identityProvider.id + 'retrieveToken'" id="identityProvider.identityProvider.id + 'retrieveToken'" value="true" onoffswitchmodel />
+                    </div>
                 </div>
             </div>
             <div class="pull-right form-actions">
-                <button kc-save>Save</button>
+                <button kc-reset data-ng-show="changed">Clear changes</button>
+                <button kc-save data-ng-show="changed">Save</button>
             </div>
         </form>
     </div>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-identity-provider.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-identity-provider.html
index 92f3e87..619ce33 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-identity-provider.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/oauth-client-identity-provider.html
@@ -10,14 +10,21 @@
         <h2 data-ng-hide="create"><span>{{oauth.name}}</span> Identity Provider Settings</h2>
         <form class="form-horizontal" name="identityProviderForm" novalidate>
             <div class="form-group" ng-repeat="identityProvider in identityProviders">
-                <legend><span class="text">{{identityProvider.name}}</span></legend>
-                <label class="col-sm-2 control-label" for="{{identityProvider.id}}">Enable</label>
+                <legend><span class="text">{{identityProvider.identityProvider.name}}</span></legend>
+                <label class="col-sm-2 control-label" for="{{identityProvider.identityProvider.id}}">Enable&nbsp;<span tooltip-placement="right" tooltip="If disabled, users can not login to the application using this identity provider." class="fa fa-info-circle"></span></label>
                 <div class="col-sm-4">
-                    <input ng-model="oauth.allowedIdentityProviders[$index]" name="identityProvider.id" id="identityProvider.id" value="identityProvider.id" kc-onoffswitch-model />
+                    <input ng-model="oauth.identityProviders[$index].id" name="identityProvider.identityProvider.id" id="identityProvider.identityProvider.id" value="identityProvider.identityProvider.id" onoffswitchmodel />
+                </div>
+                <div data-ng-show="oauth.identityProviders[$index].id">
+                    <label class="col-sm-2 control-label" for="{{identityProvider.identityProvider.id}}retrieveToken">Can Retrieve Token&nbsp;<span tooltip-placement="right" tooltip="If disabled, the application can not retrieve tokens from the identity provider." class="fa fa-info-circle"></span></label>
+                    <div class="col-sm-4">
+                        <input ng-model="oauth.identityProviders[$index].retrieveToken" name="identityProvider.identityProvider.id + 'retrieveToken'" id="identityProvider.identityProvider.id + 'retrieveToken'" value="true" onoffswitchmodel />
+                    </div>
                 </div>
             </div>
             <div class="pull-right form-actions">
-                <button kc-save>Save</button>
+                <button kc-reset data-ng-show="changed">Clear changes</button>
+                <button kc-save data-ng-show="changed">Save</button>
             </div>
         </form>
     </div>
diff --git a/model/api/src/main/java/org/keycloak/models/ClientIdentityProviderMappingModel.java b/model/api/src/main/java/org/keycloak/models/ClientIdentityProviderMappingModel.java
new file mode 100644
index 0000000..e3b8401
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/ClientIdentityProviderMappingModel.java
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models;
+
+/**
+ * @author pedroigor
+ */
+public class ClientIdentityProviderMappingModel {
+
+    private String identityProvider;
+    private boolean retrieveToken;
+
+    public String getIdentityProvider() {
+        return this.identityProvider;
+    }
+
+    public void setIdentityProvider(String identityProviderModel) {
+        this.identityProvider = identityProviderModel;
+    }
+
+    public boolean isRetrieveToken() {
+        return this.retrieveToken;
+    }
+
+    public void setRetrieveToken(boolean retrieveToken) {
+        this.retrieveToken = retrieveToken;
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 5354d04..3ebdc2a 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -98,11 +98,10 @@ public interface ClientModel {
 
     void setNotBefore(int notBefore);
 
-    void updateAllowedIdentityProviders(List<String> identityProviders);
-
-    List<String> getAllowedIdentityProviders();
-
+    void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders);
+    List<ClientIdentityProviderMappingModel> getIdentityProviders();
     boolean hasIdentityProvider(String providerId);
+    boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId);
 
     Set<ProtocolMapperModel> getProtocolMappers();
     void addProtocolMappers(Set<String> mapperIds);
diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
index 3d43fee..134d1bf 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
@@ -29,7 +29,7 @@ public class ClientEntity extends AbstractIdentifiableEntity {
     private List<String> webOrigins = new ArrayList<String>();
     private List<String> redirectUris = new ArrayList<String>();
     private List<String> scopeIds = new ArrayList<String>();
-    private List<String> allowedIdentityProviders = new ArrayList<String>();
+    private List<ClientIdentityProviderMappingEntity> identityProviders = new ArrayList<ClientIdentityProviderMappingEntity>();
     private Set<String> protocolMappers = new HashSet<String>();
 
     public String getName() {
@@ -144,12 +144,12 @@ public class ClientEntity extends AbstractIdentifiableEntity {
         this.frontchannelLogout = frontchannelLogout;
     }
 
-    public List<String> getAllowedIdentityProviders() {
-        return this.allowedIdentityProviders;
+    public List<ClientIdentityProviderMappingEntity> getIdentityProviders() {
+        return this.identityProviders;
     }
 
-    public void setAllowedIdentityProviders(List<String> allowedIdentityProviders) {
-        this.allowedIdentityProviders = allowedIdentityProviders;
+    public void setIdentityProviders(List<ClientIdentityProviderMappingEntity> identityProviders) {
+        this.identityProviders = identityProviders;
     }
 
     public Set<String> getProtocolMappers() {
diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientIdentityProviderMappingEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientIdentityProviderMappingEntity.java
new file mode 100644
index 0000000..a788aac
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/ClientIdentityProviderMappingEntity.java
@@ -0,0 +1,44 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.entities;
+
+/**
+ * @author pedroigor
+ */
+public class ClientIdentityProviderMappingEntity {
+
+    private String id;
+    private Boolean retrieveToken;
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public Boolean isRetrieveToken() {
+        return this.retrieveToken;
+    }
+
+    public void setRetrieveToken(Boolean retrieveToken) {
+        this.retrieveToken = retrieveToken;
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 522c965..7bd7cfa 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -3,6 +3,7 @@ package org.keycloak.models.utils;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.ClaimMask;
 import org.keycloak.models.ClaimTypeModel;
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.FederatedIdentityModel;
@@ -19,6 +20,7 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.representations.idm.ApplicationRepresentation;
 import org.keycloak.representations.idm.ClaimRepresentation;
 import org.keycloak.representations.idm.ClaimTypeRepresentation;
+import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentation;
 import org.keycloak.representations.idm.ClientProtocolMappingRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -262,8 +264,8 @@ public class ModelToRepresentation {
             rep.setRegisteredNodes(new HashMap<String, Integer>(applicationModel.getRegisteredNodes()));
         }
 
-        if (!applicationModel.getAllowedIdentityProviders().isEmpty()) {
-            rep.setAllowedIdentityProviders(applicationModel.getAllowedIdentityProviders());
+        if (!applicationModel.getIdentityProviders().isEmpty()) {
+            rep.setIdentityProviders(toRepresentation(applicationModel.getIdentityProviders()));
         }
 
         if (!applicationModel.getProtocolMappers().isEmpty()) {
@@ -279,6 +281,21 @@ public class ModelToRepresentation {
         return rep;
     }
 
+    private static List<ClientIdentityProviderMappingRepresentation> toRepresentation(List<ClientIdentityProviderMappingModel> identityProviders) {
+        ArrayList<ClientIdentityProviderMappingRepresentation> representations = new ArrayList<ClientIdentityProviderMappingRepresentation>();
+
+        for (ClientIdentityProviderMappingModel model : identityProviders) {
+            ClientIdentityProviderMappingRepresentation representation = new ClientIdentityProviderMappingRepresentation();
+
+            representation.setId(model.getIdentityProvider());
+            representation.setRetrieveToken(model.isRetrieveToken());
+
+            representations.add(representation);
+        }
+
+        return representations;
+    }
+
     public static OAuthClientRepresentation toRepresentation(OAuthClientModel model) {
         OAuthClientRepresentation rep = new OAuthClientRepresentation();
         rep.setId(model.getId());
@@ -301,8 +318,8 @@ public class ModelToRepresentation {
         }
         rep.setNotBefore(model.getNotBefore());
 
-        if (!model.getAllowedIdentityProviders().isEmpty()) {
-            rep.setAllowedIdentityProviders(model.getAllowedIdentityProviders());
+        if (!model.getIdentityProviders().isEmpty()) {
+            rep.setIdentityProviders(toRepresentation(model.getIdentityProviders()));
         }
 
         if (!model.getProtocolMappers().isEmpty()) {
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index f296764..2bf61e2 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -7,6 +7,7 @@ import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.BrowserSecurityHeaders;
 import org.keycloak.models.ClaimMask;
 import org.keycloak.models.ClaimTypeModel;
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
@@ -23,6 +24,7 @@ import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.ApplicationRepresentation;
 import org.keycloak.representations.idm.ClaimRepresentation;
 import org.keycloak.representations.idm.ClaimTypeRepresentation;
+import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentation;
 import org.keycloak.representations.idm.ClientProtocolMappingRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -473,17 +475,7 @@ public class RepresentationToModel {
             applicationModel.setProtocolMappers(ids);
         }
 
-        List<String> allowedIdentityProviders = resourceRep.getAllowedIdentityProviders();
-
-        if (allowedIdentityProviders == null || allowedIdentityProviders.isEmpty()) {
-            allowedIdentityProviders = new ArrayList<String>();
-
-            for (IdentityProviderModel identityProvider : realm.getIdentityProviders()) {
-                allowedIdentityProviders.add(identityProvider.getId());
-            }
-        }
-
-        applicationModel.updateAllowedIdentityProviders(allowedIdentityProviders);
+        applicationModel.updateAllowedIdentityProviders(toModel(resourceRep.getIdentityProviders(), realm));
 
         return applicationModel;
     }
@@ -536,9 +528,7 @@ public class RepresentationToModel {
             setClaims(resource, rep.getClaims());
         }
 
-        if (rep.getAllowedIdentityProviders() != null) {
-            resource.updateAllowedIdentityProviders(rep.getAllowedIdentityProviders());
-        }
+        updateClientIdentityProvides(rep.getIdentityProviders(), resource);
     }
 
     public static void setClaims(ClientModel model, ClaimRepresentation rep) {
@@ -613,17 +603,7 @@ public class RepresentationToModel {
     public static OAuthClientModel createOAuthClient(OAuthClientRepresentation rep, RealmModel realm) {
         OAuthClientModel model = createOAuthClient(rep.getId(), rep.getName(), realm);
 
-        List<String> allowedIdentityProviders = rep.getAllowedIdentityProviders();
-
-        if (allowedIdentityProviders == null || allowedIdentityProviders.isEmpty()) {
-            allowedIdentityProviders = new ArrayList<String>();
-
-            for (IdentityProviderModel identityProvider : realm.getIdentityProviders()) {
-                allowedIdentityProviders.add(identityProvider.getId());
-            }
-        }
-
-        model.updateAllowedIdentityProviders(allowedIdentityProviders);
+        model.updateAllowedIdentityProviders(toModel(rep.getIdentityProviders(), realm));
 
         updateOAuthClient(rep, model);
         return model;
@@ -667,9 +647,7 @@ public class RepresentationToModel {
             }
         }
 
-        if (rep.getAllowedIdentityProviders() != null) {
-            model.updateAllowedIdentityProviders(rep.getAllowedIdentityProviders());
-        }
+        updateClientIdentityProvides(rep.getIdentityProviders(), model);
 
         if (rep.getProtocolMappers() != null) {
             Set<String> ids = new HashSet<String>();
@@ -868,4 +846,48 @@ public class RepresentationToModel {
         model.setConfig(rep.getConfig());
         return model;
     }
+
+    private static List<ClientIdentityProviderMappingModel> toModel(List<ClientIdentityProviderMappingRepresentation> repIdentityProviders, RealmModel realm) {
+        List<ClientIdentityProviderMappingModel> allowedIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
+
+        if (repIdentityProviders == null || repIdentityProviders.isEmpty()) {
+            allowedIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
+
+            for (IdentityProviderModel identityProvider : realm.getIdentityProviders()) {
+                ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
+
+                identityProviderMapping.setIdentityProvider(identityProvider.getId());
+
+                allowedIdentityProviders.add(identityProviderMapping);
+            }
+        } else {
+            for (ClientIdentityProviderMappingRepresentation rep : repIdentityProviders) {
+                ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
+
+                identityProviderMapping.setIdentityProvider(rep.getId());
+                identityProviderMapping.setRetrieveToken(rep.isRetrieveToken());
+
+                allowedIdentityProviders.add(identityProviderMapping);
+            }
+        }
+
+        return allowedIdentityProviders;
+    }
+
+    private static void updateClientIdentityProvides(List<ClientIdentityProviderMappingRepresentation> identityProviders, ClientModel resource) {
+        if (identityProviders != null) {
+            List<ClientIdentityProviderMappingModel> allowedIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
+
+            for (ClientIdentityProviderMappingRepresentation mappingRepresentation : identityProviders) {
+                ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
+
+                identityProviderMapping.setIdentityProvider(mappingRepresentation.getId());
+                identityProviderMapping.setRetrieveToken(mappingRepresentation.isRetrieveToken());
+
+                allowedIdentityProviders.add(identityProviderMapping);
+            }
+
+            resource.updateAllowedIdentityProviders(allowedIdentityProviders);
+        }
+    }
 }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
index 0fc38bc..a17cc7c 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
@@ -1,5 +1,6 @@
 package org.keycloak.models.cache;
 
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
@@ -263,15 +264,15 @@ public abstract class ClientAdapter implements ClientModel {
     }
 
     @Override
-    public void updateAllowedIdentityProviders(List<String> identityProviders) {
+    public void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
         getDelegateForUpdate();
         updatedClient.updateAllowedIdentityProviders(identityProviders);
     }
 
     @Override
-    public List<String> getAllowedIdentityProviders() {
-        if (updatedClient != null) return updatedClient.getAllowedIdentityProviders();
-        return cachedClient.getAllowedIdentityProviders();
+    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
+        if (updatedClient != null) return updatedClient.getIdentityProviders();
+        return cachedClient.getIdentityProviders();
     }
 
     @Override
@@ -281,6 +282,12 @@ public abstract class ClientAdapter implements ClientModel {
     }
 
     @Override
+    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
+        if (updatedClient != null) return updatedClient.isAllowedRetrieveTokenFromIdentityProvider(providerId);
+        return cachedClient.isAllowedRetrieveTokenFromIdentityProvider(providerId);
+    }
+
+    @Override
     public Set<ProtocolMapperModel> getProtocolMappers() {
         if (updatedClient != null) return updatedClient.getProtocolMappers();
         return cachedClient.getProtocolClaimMappings();    }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index 1029713..e9a8a89 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -1,5 +1,6 @@
 package org.keycloak.models.cache.entities;
 
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
@@ -35,7 +36,7 @@ public class CachedClient {
     protected int notBefore;
     protected Set<String> scope = new HashSet<String>();
     protected Set<String> webOrigins = new HashSet<String>();
-    private List<String> allowedIdentityProviders = new ArrayList<String>();
+    private List<ClientIdentityProviderMappingModel> identityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
     private Set<ProtocolMapperModel> protocolClaimMappings = new HashSet<ProtocolMapperModel>();
 
     public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) {
@@ -57,7 +58,7 @@ public class CachedClient {
         for (RoleModel role : model.getScopeMappings())  {
             scope.add(role.getId());
         }
-        this.allowedIdentityProviders = model.getAllowedIdentityProviders();
+        this.identityProviders = model.getIdentityProviders();
         protocolClaimMappings.addAll(model.getProtocolMappers());
     }
 
@@ -125,15 +126,31 @@ public class CachedClient {
         return frontchannelLogout;
     }
 
-    public List<String> getAllowedIdentityProviders() {
-        return this.allowedIdentityProviders;
+    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
+        return this.identityProviders;
     }
 
     public boolean hasIdentityProvider(String providerId) {
-        return this.allowedIdentityProviders.contains(providerId);
+        for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
+            if (model.getIdentityProvider().equals(providerId)) {
+                return true;
+            }
+        }
+
+        return false;
     }
 
     public Set<ProtocolMapperModel> getProtocolClaimMappings() {
         return protocolClaimMappings;
     }
+
+    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
+        for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
+            if (model.getIdentityProvider().equals(providerId)) {
+                return model.isRetrieveToken();
+            }
+        }
+
+        return false;
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index c437014..04af5ee 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -1,14 +1,15 @@
 package org.keycloak.models.jpa;
 
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.jpa.entities.ClientEntity;
+import org.keycloak.models.jpa.entities.ClientIdentityProviderMappingEntity;
 import org.keycloak.models.jpa.entities.IdentityProviderEntity;
 import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
-import org.keycloak.models.jpa.entities.RealmEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
 import org.keycloak.models.jpa.entities.ScopeMappingEntity;
 
@@ -303,47 +304,96 @@ public abstract class ClientAdapter implements ClientModel {
     }
 
     @Override
-    public void updateAllowedIdentityProviders(List<String> identityProviders) {
-        Collection<IdentityProviderEntity> entities = entity.getAllowedIdentityProviders();
+    public void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
+        Collection<ClientIdentityProviderMappingEntity> entities = entity.getIdentityProviders();
         Set<String> already = new HashSet<String>();
-        List<IdentityProviderEntity> remove = new ArrayList<IdentityProviderEntity>();
-        for (IdentityProviderEntity rel : entities) {
-            if (!contains(rel.getId(), identityProviders.toArray(new String[identityProviders.size()]))) {
-                remove.add(rel);
+        List<ClientIdentityProviderMappingEntity> remove = new ArrayList<ClientIdentityProviderMappingEntity>();
+
+        for (ClientIdentityProviderMappingEntity entity : entities) {
+            IdentityProviderEntity identityProvider = entity.getIdentityProvider();
+            boolean toRemove = true;
+
+            for (ClientIdentityProviderMappingModel model : identityProviders) {
+                if (model.getIdentityProvider().equals(identityProvider.getId())) {
+                    toRemove = false;
+                    break;
+                }
+            }
+
+            if (toRemove) {
+                remove.add(entity);
             } else {
-                already.add(rel.getId());
+                already.add(entity.getIdentityProvider().getId());
             }
         }
-        for (IdentityProviderEntity entity : remove) {
+        for (ClientIdentityProviderMappingEntity entity : remove) {
             entities.remove(entity);
+            em.remove(entity);
         }
         em.flush();
-        for (String providerId : identityProviders) {
-            if (!already.contains(providerId)) {
-                TypedQuery<IdentityProviderEntity> query = em.createNamedQuery("findIdentityProviderById", IdentityProviderEntity.class).setParameter("id", providerId);
-                IdentityProviderEntity providerEntity = query.getSingleResult();
-                entities.add(providerEntity);
+        for (ClientIdentityProviderMappingModel model : identityProviders) {
+            ClientIdentityProviderMappingEntity mappingEntity = null;
+
+            if (!already.contains(model.getIdentityProvider())) {
+                mappingEntity = new ClientIdentityProviderMappingEntity();
+                entities.add(mappingEntity);
+            } else {
+                for (ClientIdentityProviderMappingEntity entity : entities) {
+                    if (entity.getIdentityProvider().getId().equals(model.getIdentityProvider())) {
+                        mappingEntity = entity;
+                        break;
+                    }
+                }
             }
+
+            TypedQuery<IdentityProviderEntity> query = em.createNamedQuery("findIdentityProviderById", IdentityProviderEntity.class).setParameter("id", model.getIdentityProvider());
+            IdentityProviderEntity identityProviderEntity = query.getSingleResult();
+
+            mappingEntity.setIdentityProvider(identityProviderEntity);
+            mappingEntity.setClient(this.entity);
+            mappingEntity.setRetrieveToken(model.isRetrieveToken());
+
+            em.persist(mappingEntity);
         }
         em.flush();
     }
 
     @Override
-    public List<String> getAllowedIdentityProviders() {
-        Collection<IdentityProviderEntity> entities = entity.getAllowedIdentityProviders();
-        List<String> providers = new ArrayList<String>();
+    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
+        List<ClientIdentityProviderMappingModel> models = new ArrayList<ClientIdentityProviderMappingModel>();
+
+        for (ClientIdentityProviderMappingEntity entity : this.entity.getIdentityProviders()) {
+            ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
 
-        for (IdentityProviderEntity entity : entities) {
-            providers.add(entity.getId());
+            model.setIdentityProvider(entity.getIdentityProvider().getId());
+            model.setRetrieveToken(entity.isRetrieveToken());
+
+            models.add(model);
         }
 
-        return providers;
+        return models;
     }
 
     @Override
     public boolean hasIdentityProvider(String providerId) {
-        List<String> allowedIdentityProviders = getAllowedIdentityProviders();
-        return allowedIdentityProviders.contains(providerId);
+        for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
+            if (model.getIdentityProvider().equals(providerId)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
+        for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
+            if (model.getIdentityProvider().equals(providerId)) {
+                return model.isRetrieveToken();
+            }
+        }
+
+        return false;
     }
 
     public static boolean contains(String str, String[] array) {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index 817fd80..dcf33cb 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -73,9 +73,8 @@ public abstract class ClientEntity {
     @CollectionTable(name="CLIENT_ATTRIBUTES", joinColumns={ @JoinColumn(name="CLIENT_ID") })
     protected Map<String, String> attributes = new HashMap<String, String>();
 
-    @OneToMany(fetch = FetchType.LAZY)
-    @JoinTable(name="CLIENT_ALLOWED_IDENTITY_PROVIDER", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="INTERNAL_ID")})
-    Collection<IdentityProviderEntity> allowedIdentityProviders = new ArrayList<IdentityProviderEntity>();
+    @OneToMany(fetch = FetchType.LAZY, mappedBy = "client", cascade = CascadeType.REMOVE)
+    Collection<ClientIdentityProviderMappingEntity> identityProviders = new ArrayList<ClientIdentityProviderMappingEntity>();
 
     @OneToMany(fetch = FetchType.LAZY)
     @JoinTable(name="CLIENT_PROTOCOL_MAPPER", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="MAPPING_ID")})
@@ -193,12 +192,12 @@ public abstract class ClientEntity {
         this.frontchannelLogout = frontchannelLogout;
     }
 
-    public Collection<IdentityProviderEntity> getAllowedIdentityProviders() {
-        return this.allowedIdentityProviders;
+    public Collection<ClientIdentityProviderMappingEntity> getIdentityProviders() {
+        return this.identityProviders;
     }
 
-    public void setAllowedIdentityProviders(Collection<IdentityProviderEntity> allowedIdentityProviders) {
-        this.allowedIdentityProviders = allowedIdentityProviders;
+    public void setIdentityProviders(Collection<ClientIdentityProviderMappingEntity> identityProviders) {
+        this.identityProviders = identityProviders;
     }
 
     public Collection<ProtocolMapperEntity> getProtocolMappers() {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientIdentityProviderMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientIdentityProviderMappingEntity.java
new file mode 100755
index 0000000..fe8485d
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientIdentityProviderMappingEntity.java
@@ -0,0 +1,121 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author pedroigor
+ */
+@Table(name="CLIENT_IDENTITY_PROVIDER_MAPPING")
+@Entity
+@IdClass(ClientIdentityProviderMappingEntity.Key.class)
+public class ClientIdentityProviderMappingEntity {
+
+    @Id
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "CLIENT_ID")
+    private ClientEntity client;
+
+    @Id
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "IDENTITY_PROVIDER_ID")
+    private IdentityProviderEntity identityProvider;
+
+    @Column(name = "RETRIEVE_TOKEN")
+    private boolean retrieveToken;
+
+    public ClientEntity getClient() {
+        return this.client;
+    }
+
+    public void setClient(ClientEntity client) {
+        this.client = client;
+    }
+
+    public IdentityProviderEntity getIdentityProvider() {
+        return this.identityProvider;
+    }
+
+    public void setIdentityProvider(IdentityProviderEntity identityProvider) {
+        this.identityProvider = identityProvider;
+    }
+
+    public void setRetrieveToken(boolean retrieveToken) {
+        this.retrieveToken = retrieveToken;
+    }
+
+    public boolean isRetrieveToken() {
+        return retrieveToken;
+    }
+
+    public static class Key implements Serializable {
+
+        private ClientEntity client;
+        private IdentityProviderEntity identityProvider;
+
+        public Key() {
+        }
+
+        public Key(ClientEntity client, IdentityProviderEntity identityProvider) {
+            this.client = client;
+            this.identityProvider = identityProvider;
+        }
+
+        public ClientEntity getUser() {
+            return client;
+        }
+
+        public IdentityProviderEntity getIdentityProvider() {
+            return identityProvider;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Key key = (Key) o;
+
+            if (identityProvider != null ? !identityProvider.getId().equals(key.identityProvider.getId()) : key.identityProvider != null)
+                return false;
+            if (client != null ? !client.getId().equals(key.client != null ? key.client.getId() : null) : key.client != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = client != null ? client.getId().hashCode() : 0;
+            result = 31 * result + (identityProvider != null ? identityProvider.hashCode() : 0);
+            return result;
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ClientIdentityProviderMappingEntity key = (ClientIdentityProviderMappingEntity) o;
+
+        if (identityProvider != null ? !identityProvider.getId().equals(key.identityProvider.getId()) : key.identityProvider != null)
+            return false;
+        if (client != null ? !client.getId().equals(key.client != null ? key.client.getId() : null) : key.client != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = client != null ? client.getId().hashCode() : 0;
+        result = 31 * result + (identityProvider != null ? identityProvider.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index 3c47282..c0202c1 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -2,6 +2,7 @@ package org.keycloak.models.mongo.keycloak.adapters;
 
 import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
 import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
@@ -9,6 +10,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RealmProvider;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.entities.ClientEntity;
+import org.keycloak.models.entities.ClientIdentityProviderMappingEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
 import org.keycloak.models.mongo.utils.MongoModelUtils;
 
@@ -323,24 +325,58 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
     }
 
     @Override
-    public void updateAllowedIdentityProviders(List<String> identityProviders) {
-        List<String> providerIds = new ArrayList<String>();
-        for (String providerId : identityProviders) {
-            providerIds.add(providerId);
+    public void updateAllowedIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
+        List<ClientIdentityProviderMappingEntity> stored = getMongoEntityAsClient().getIdentityProviders();
+
+        for (ClientIdentityProviderMappingModel model : identityProviders) {
+            ClientIdentityProviderMappingEntity entity = new ClientIdentityProviderMappingEntity();
+
+            entity.setId(model.getIdentityProvider());
+            entity.setRetrieveToken(model.isRetrieveToken());
         }
 
-        getMongoEntityAsClient().setAllowedIdentityProviders(identityProviders);
+        getMongoEntityAsClient().setIdentityProviders(stored);
         updateMongoEntity();
     }
 
     @Override
-    public List<String> getAllowedIdentityProviders() {
-        return getMongoEntityAsClient().getAllowedIdentityProviders();
+    public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
+        List<ClientIdentityProviderMappingModel> models = new ArrayList<ClientIdentityProviderMappingModel>();
+
+        for (ClientIdentityProviderMappingEntity entity : getMongoEntityAsClient().getIdentityProviders()) {
+            ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
+
+            model.setIdentityProvider(entity.getId());
+            model.setRetrieveToken(entity.isRetrieveToken());
+
+            models.add(model);
+        }
+
+        return models;
     }
 
     @Override
     public boolean hasIdentityProvider(String providerId) {
-        List<String> allowedIdentityProviders = getMongoEntityAsClient().getAllowedIdentityProviders();
-        return allowedIdentityProviders.contains(providerId);
+        for (ClientIdentityProviderMappingEntity identityProviderMappingModel : getMongoEntityAsClient().getIdentityProviders()) {
+            String identityProvider = identityProviderMappingModel.getId();
+
+            if (identityProvider.equals(providerId)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
+        for (ClientIdentityProviderMappingEntity identityProviderMappingModel : getMongoEntityAsClient().getIdentityProviders()) {
+            if (identityProviderMappingModel.getId().equals(providerId)) {
+                return identityProviderMappingModel.isRetrieveToken();
+            }
+        }
+
+        return false;
     }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index e8b184e..bac9b03 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -1,6 +1,7 @@
 package org.keycloak.services.resources.admin;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
@@ -17,6 +18,7 @@ import javax.ws.rs.GET;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Response;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -63,11 +65,15 @@ public class IdentityProviderResource {
 
     private void removeClientIdentityProviders(List<? extends ClientModel> clients, IdentityProviderModel identityProvider) {
         for (ClientModel clientModel : clients) {
-            List<String> allowedIdentityProviders = clientModel.getAllowedIdentityProviders();
+            List<ClientIdentityProviderMappingModel> identityProviders = clientModel.getIdentityProviders();
 
-            allowedIdentityProviders.remove(identityProvider.getId());
+            for (ClientIdentityProviderMappingModel providerMappingModel : new ArrayList<ClientIdentityProviderMappingModel>(identityProviders)) {
+                if (providerMappingModel.getIdentityProvider().equals(identityProvider.getId())) {
+                    identityProviders.remove(providerMappingModel);
+                }
+            }
 
-            clientModel.updateAllowedIdentityProviders(allowedIdentityProviders);
+            clientModel.updateAllowedIdentityProviders(identityProviders);
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
index d44e464..d7d1a67 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
@@ -7,6 +7,7 @@ import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.broker.provider.IdentityProviderFactory;
+import org.keycloak.models.ClientIdentityProviderMappingModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
@@ -179,9 +180,12 @@ public class IdentityProvidersResource {
 
     private void updateClientIdentityProviders(List<? extends ClientModel> clients, IdentityProviderRepresentation identityProvider) {
         for (ClientModel clientModel : clients) {
-            List<String> allowedIdentityProviders = clientModel.getAllowedIdentityProviders();
+            List<ClientIdentityProviderMappingModel> allowedIdentityProviders = clientModel.getIdentityProviders();
+            ClientIdentityProviderMappingModel providerMappingModel = new ClientIdentityProviderMappingModel();
 
-            allowedIdentityProviders.add(identityProvider.getId());
+            providerMappingModel.setIdentityProvider(identityProvider.getId());
+
+            allowedIdentityProviders.add(providerMappingModel);
 
             clientModel.updateAllowedIdentityProviders(allowedIdentityProviders);
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 5f9501e..7fb4209 100644
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -186,6 +186,10 @@ public class IdentityBrokerService {
                     return corsResponse(badRequest("Client [" + audience + "] not authorized."), clientModel);
                 }
 
+                if (!clientModel.isAllowedRetrieveTokenFromIdentityProvider(providerId)) {
+                    return corsResponse(badRequest("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
+                }
+
                 if (OAuthClientModel.class.isInstance(clientModel) && !forceRetrieval) {
                     return corsResponse(Flows.forms(this.session, this.realmModel, clientModel, this.uriInfo)
                             .setClientSessionCode(authManager.extractAuthorizationHeaderToken(this.request.getHttpHeaders()))
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index 6921ec3..dd034c1 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -25,6 +25,8 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientIdentityProviderMappingModel;
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
@@ -156,11 +158,18 @@ public abstract class AbstractIdentityProviderTest {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
         RealmModel realm = getRealm();
         ApplicationModel applicationModel = realm.getApplicationByName("test-app");
-        List<String> allowedIdentityProviders = applicationModel.getAllowedIdentityProviders();
+        List<ClientIdentityProviderMappingModel> allowedIdentityProviders = applicationModel.getIdentityProviders();
+        ClientIdentityProviderMappingModel mapping = null;
 
-        assertTrue(allowedIdentityProviders.contains(identityProviderModel.getId()));
+        for (ClientIdentityProviderMappingModel model : allowedIdentityProviders) {
+            if (model.getIdentityProvider().equals(identityProviderModel.getId())) {
+                mapping = model;
+            }
+        }
 
-        allowedIdentityProviders.remove(identityProviderModel.getId());
+        assertNotNull(mapping);
+
+        allowedIdentityProviders.remove(mapping);
 
         this.driver.navigate().to("http://localhost:8081/test-app/");
 
@@ -173,7 +182,7 @@ public abstract class AbstractIdentityProviderTest {
 
         }
 
-        allowedIdentityProviders.add(identityProviderModel.getId());
+        allowedIdentityProviders.add(mapping);
 
         applicationModel.updateAllowedIdentityProviders(allowedIdentityProviders);
 
@@ -317,6 +326,18 @@ public abstract class AbstractIdentityProviderTest {
 
         assertNotNull(identityModel.getToken());
 
+        ClientModel clientModel = realm.findClient("test-app");
+        ClientIdentityProviderMappingModel providerMappingModel = null;
+
+        for (ClientIdentityProviderMappingModel identityProviderMappingModel : clientModel.getIdentityProviders()) {
+            if (identityProviderMappingModel.getIdentityProvider().equals(getProviderId())) {
+                providerMappingModel = identityProviderMappingModel;
+                break;
+            }
+        }
+
+        providerMappingModel.setRetrieveToken(false);
+
         UserSessionStatus userSessionStatus = retrieveSessionStatus();
         String accessToken = userSessionStatus.getAccessTokenString();
         URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), realm.getName());
@@ -331,6 +352,14 @@ public abstract class AbstractIdentityProviderTest {
         WebTarget tokenEndpoint = client.target(tokenEndpointUrl);
         Response response = tokenEndpoint.request().get();
 
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+
+        providerMappingModel.setRetrieveToken(true);
+
+        client = ClientBuilder.newBuilder().register(authFilter).build();
+        tokenEndpoint = client.target(tokenEndpointUrl);
+        response = tokenEndpoint.request().get();
+
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         assertNotNull(response.readEntity(String.class));
 
@@ -375,6 +404,18 @@ public abstract class AbstractIdentityProviderTest {
 
         assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.CODE));
 
+        ClientModel clientModel = getRealm().findClient("third-party");
+        ClientIdentityProviderMappingModel providerMappingModel = null;
+
+        for (ClientIdentityProviderMappingModel identityProviderMappingModel : clientModel.getIdentityProviders()) {
+            if (identityProviderMappingModel.getIdentityProvider().equals(getProviderId())) {
+                providerMappingModel = identityProviderMappingModel;
+                break;
+            }
+        }
+
+        providerMappingModel.setRetrieveToken(true);
+
         AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get(OAuth2Constants.CODE), "password");
         URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), getRealm().getName());
         String authHeader = "Bearer " + accessToken.getAccessToken();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
index d654d1e..8f43860 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
@@ -25,6 +25,8 @@ import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
 import org.keycloak.broker.saml.SAMLIdentityProvider;
 import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
 import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
+import org.keycloak.models.ClientIdentityProviderMappingModel;
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.representations.idm.RealmRepresentation;
@@ -113,6 +115,31 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertFalse(identityProviderModel.isAuthenticateByDefault());
     }
 
+    @Test
+    public void testApplicationIdentityProviders() throws Exception {
+        RealmModel realm = installTestRealm();
+
+        ClientModel client = realm.findClient("test-app-with-allowed-providers");
+        List<ClientIdentityProviderMappingModel> identityProviders = client.getIdentityProviders();
+
+        assertEquals(1, identityProviders.size());
+
+        ClientIdentityProviderMappingModel identityProviderMappingModel = identityProviders.get(0);
+
+        assertEquals("kc-oidc-idp", identityProviderMappingModel.getIdentityProvider());
+        assertEquals(false, identityProviderMappingModel.isRetrieveToken());
+
+        identityProviders.remove(identityProviderMappingModel);
+
+        client.updateAllowedIdentityProviders(identityProviders);
+
+        client = realm.findClientById(client.getId());
+        identityProviders = client.getIdentityProviders();
+
+        assertEquals(0, identityProviders.size());
+    }
+
+
     private void assertIdentityProviderConfig(List<IdentityProviderModel> identityProviders) {
         assertFalse(identityProviders.isEmpty());
 
diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
index 322cebe..c567c17 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
@@ -197,8 +197,11 @@
             "/test-app/*"
           ],
           "webOrigins": [],
-          "allowedIdentityProviders": [
-            "kc-oidc-idp"
+          "identityProviders": [
+            {
+              "id": "kc-oidc-idp",
+              "retrieveToken": false
+            }
           ]
         }
     ],