keycloak-uncached

Merge upstream/master

12/1/2015 9:51:57 AM

Changes

Details

diff --git a/common/src/main/java/org/keycloak/common/util/CollectionUtil.java b/common/src/main/java/org/keycloak/common/util/CollectionUtil.java
index 747b0bb..f0fda16 100644
--- a/common/src/main/java/org/keycloak/common/util/CollectionUtil.java
+++ b/common/src/main/java/org/keycloak/common/util/CollectionUtil.java
@@ -23,4 +23,19 @@ public class CollectionUtil {
         }
         return sb.toString();
     }
+
+    // Return true if all items from col1 are in col2 and viceversa. Order is not taken into account
+    public static <T> boolean collectionEquals(Collection<T> col1, Collection<T> col2) {
+        if (col1.size() != col2.size()) {
+            return false;
+        }
+
+        for (T item : col1) {
+            if (!col2.contains(item)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
 }
diff --git a/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index bc2635c..d1e7ac6 100755
--- a/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/connections/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -69,7 +69,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
 
                     // Backwards compatibility
                     if (cacheManager.getCacheConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME) == null) {
-                        logger.warnf("No configuration provided for '%s' cache. Using '%s' configuration as template",
+                        logger.debugf("No configuration provided for '%s' cache. Using '%s' configuration as template",
                                 InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, InfinispanConnectionProvider.SESSION_CACHE_NAME);
 
                         Configuration sessionCacheConfig = cacheManager.getCacheConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME);
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml
index eadbdcf..7165348 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml
@@ -48,7 +48,7 @@
 
         <addColumn tableName="IDENTITY_PROVIDER">
             <column name="FIRST_BROKER_LOGIN_FLOW_ID" type="VARCHAR(36)">
-                <constraints nullable="false"/>
+                <constraints nullable="true"/>
             </column>
         </addColumn>
 
@@ -56,6 +56,7 @@
             <column name="ACCESS_TOKEN_LIFE_IMPLICIT" type="INT" defaultValueNumeric="0"/>
         </addColumn>
 
+        <dropDefaultValue tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LGN_MD" />
         <dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LGN_MD"/>
 
         <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_GROUP" tableName="KEYCLOAK_GROUP"/>
@@ -83,13 +84,14 @@
             <column name="IMPLICIT_FLOW_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
                 <constraints nullable="false"/>
             </column>
-            <column name="DIRECT_ACCESS_GRANTS_ENABLED" type="BOOLEAN" defaultValueBoolean="true">
+            <column name="DIRECT_ACCESS_GRANTS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
                 <constraints nullable="false"/>
             </column>
         </addColumn>
 
         <update tableName="CLIENT">
             <column name="STANDARD_FLOW_ENABLED" valueBoolean="false"/>
+            <column name="DIRECT_ACCESS_GRANTS_ENABLED" valueBoolean="true"/>
             <where>DIRECT_GRANTS_ONLY = :value</where>
             <whereParams>
                 <param valueBoolean="true" />
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java
index 666a3af..5b3b38a 100644
--- a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java
@@ -27,7 +27,7 @@ public class Update1_7_0 extends Update {
                 boolean directGrantsOnly = client.getBoolean("directGrantsOnly", false);
                 client.append("standardFlowEnabled", !directGrantsOnly);
                 client.append("implicitFlowEnabled", false);
-                client.append("directAccessGrantsEnabled", true);
+                client.append("directAccessGrantsEnabled", directGrantsOnly);
                 client.removeField("directGrantsOnly");
 
                 clients.save(client);
diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index b552d1b..4b38a76 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -27,6 +27,8 @@ public interface OAuth2Constants {
 
     String AUTHORIZATION_CODE = "authorization_code";
 
+    String IMPLICIT = "implicit";
+
     String PASSWORD = "password";
 
     String CLIENT_CREDENTIALS = "client_credentials";
diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
index aef643c..a648f12 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
@@ -30,6 +30,7 @@ public class ClientRepresentation {
     protected Boolean implicitFlowEnabled;
     protected Boolean directAccessGrantsEnabled;
     protected Boolean serviceAccountsEnabled;
+    @Deprecated
     protected Boolean directGrantsOnly;
     protected Boolean publicClient;
     protected Boolean frontchannelLogout;
@@ -216,6 +217,7 @@ public class ClientRepresentation {
         this.serviceAccountsEnabled = serviceAccountsEnabled;
     }
 
+    @Deprecated
     public Boolean isDirectGrantsOnly() {
         return directGrantsOnly;
     }
diff --git a/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java b/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
index 1ff32fc..c76f5c7 100644
--- a/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
@@ -14,9 +14,9 @@ public class OIDCClientRepresentation {
 
     private String token_endpoint_auth_method;
 
-    private String grant_types;
+    private List<String> grant_types;
 
-    private String response_types;
+    private List<String> response_types;
 
     private String client_id;
 
@@ -68,19 +68,19 @@ public class OIDCClientRepresentation {
         this.token_endpoint_auth_method = token_endpoint_auth_method;
     }
 
-    public String getGrantTypes() {
+    public List<String> getGrantTypes() {
         return grant_types;
     }
 
-    public void setGrantTypes(String grantTypes) {
+    public void setGrantTypes(List<String> grantTypes) {
         this.grant_types = grantTypes;
     }
 
-    public String getResponseTypes() {
+    public List<String> getResponseTypes() {
         return response_types;
     }
 
-    public void setResponseTypes(String responseTypes) {
+    public void setResponseTypes(List<String> responseTypes) {
         this.response_types = responseTypes;
     }
 
diff --git a/distribution/server-overlay/eap6/eap6-server-modules/build.xml b/distribution/server-overlay/eap6/eap6-server-modules/build.xml
index e8086dc..09be9a4 100755
--- a/distribution/server-overlay/eap6/eap6-server-modules/build.xml
+++ b/distribution/server-overlay/eap6/eap6-server-modules/build.xml
@@ -71,6 +71,10 @@
             <maven-resource group="com.google.zxing" artifact="core"/>
         </module-def>
 
+        <module-def name="org.jboss.aesh" slot="0.65">
+            <maven-resource group="org.jboss.aesh" artifact="aesh"/>
+        </module-def>
+
         <module-def name="com.google.zxing.javase">
             <maven-resource group="com.google.zxing" artifact="javase"/>
         </module-def>
@@ -246,6 +250,10 @@
             <maven-resource group="org.keycloak" artifact="keycloak-saml-protocol"/>
         </module-def>
 
+        <module-def name="org.keycloak.keycloak-wildfly-adduser">
+            <maven-resource group="org.keycloak" artifact="keycloak-wildfly-adduser"/>
+        </module-def>
+
         <!-- mongo -->
 
         <module-def name="org.keycloak.keycloak-connections-mongo">
diff --git a/distribution/server-overlay/eap6/eap6-server-modules/pom.xml b/distribution/server-overlay/eap6/eap6-server-modules/pom.xml
index b3225fd..1d5d272 100755
--- a/distribution/server-overlay/eap6/eap6-server-modules/pom.xml
+++ b/distribution/server-overlay/eap6/eap6-server-modules/pom.xml
@@ -39,6 +39,10 @@
             <artifactId>keycloak-wildfly-extensions</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-wildfly-adduser</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk15on</artifactId>
         </dependency>
@@ -46,6 +50,10 @@
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcpkix-jdk15on</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.jboss.aesh</groupId>
+            <artifactId>aesh</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/jboss/aesh/0.65/module.xml b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/jboss/aesh/0.65/module.xml
new file mode 100644
index 0000000..8a9d6f8
--- /dev/null
+++ b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/jboss/aesh/0.65/module.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2010, Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags. See the copyright.txt file in the
+  ~ distribution for a full listing of individual contributors.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.jboss.aesh" slot="0.65">
+    <properties>
+        <property name="jboss.api" value="private"/>
+    </properties>
+
+    <resources>
+        <!-- Insert resources here -->
+    </resources>
+
+    <dependencies>
+        <module name="org.fusesource.jansi" />
+    </dependencies>
+</module>
diff --git a/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adduser/main/module.xml b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adduser/main/module.xml
new file mode 100755
index 0000000..e781d10
--- /dev/null
+++ b/distribution/server-overlay/eap6/eap6-server-modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adduser/main/module.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-wildfly-adduser">
+    <main-class name="org.keycloak.wildfly.adduser.AddUser"/>
+    <resources>
+        <!-- Insert resources here -->
+    </resources>
+    <dependencies>
+        <module name="org.keycloak.keycloak-common"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-model-api"/>
+        <module name="org.jboss.aesh" slot="0.65"/>
+        <module name="org.jboss.as.domain-management"/>
+        <module name="org.codehaus.jackson.jackson-core-asl"/>
+    </dependencies>
+</module>
diff --git a/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml b/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml
index b3324df..8510f2b 100755
--- a/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml
+++ b/distribution/server-overlay/eap6/eap6-server-overlay/assembly.xml
@@ -52,6 +52,11 @@
             <source>src/main/providers/README.txt</source>
             <outputDirectory>standalone/configuration/providers</outputDirectory>
         </file>
+        <file>
+            <source>../../../feature-packs/server-feature-pack/src/main/resources/content/bin/add-user.sh</source>
+            <outputDirectory>bin</outputDirectory>
+            <destName>add-user-keycloak.sh</destName>
+        </file>
     </files>
 
 </assembly>
diff --git a/distribution/server-overlay/wf9-server-overlay/assembly.xml b/distribution/server-overlay/wf9-server-overlay/assembly.xml
index 8f0daa2..5b96e2d 100755
--- a/distribution/server-overlay/wf9-server-overlay/assembly.xml
+++ b/distribution/server-overlay/wf9-server-overlay/assembly.xml
@@ -15,6 +15,7 @@
             <includes>
                 <include>com/google/zxing/**</include>
                 <include>org/freemarker/**</include>
+                <include>org/jboss/aesh/**</include>
                 <include>org/keycloak/**</include>
                 <include>org/liquibase/**</include>
                 <include>org/mongodb/**</include>
@@ -71,6 +72,11 @@
             <source>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/keycloak-server.json</source>
             <outputDirectory>standalone/configuration</outputDirectory>
         </file>
+        <file>
+            <source>${project.build.directory}/unpacked/keycloak-${project.version}/bin/add-user.sh</source>
+            <outputDirectory>bin</outputDirectory>
+            <destName>add-user-keycloak.sh</destName>
+        </file>
     </files>
 
 </assembly>
diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/javascript-adapter.xml b/docbook/auth-server-docs/reference/en/en-US/modules/javascript-adapter.xml
index 2036afb..e0d78f3 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/javascript-adapter.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/javascript-adapter.xml
@@ -96,15 +96,15 @@ keycloak.init({ onLoad: 'login-required' })
     }
 </script>
 
-<button onclick="loadData()">Submit</button>
+<button onclick="reloadData()">Submit</button>
 ]]></programlisting>
      </para>
     <para>
         The <literal>loadData()</literal> method builds an HTTP request setting the <literal>Authorization</literal>
         header to a bearer token.  The <literal>keycloak.token</literal> points to the access token the browser obtained
         when it logged you in.  The <literal>loadFailure()</literal> method is invoked on a failure.  The <literal>reloadData()</literal>
-        function calls <literal>keycloak.onValidAccessToken()</literal> passing in the <literal>loadData()</literal> and
-        <literal>loadFailure()</literal> callbacks.  The <literal>keycloak.onValidAcessToken()</literal> method checks to
+        function calls <literal>keycloak.updateToken()</literal> passing in the <literal>loadData()</literal> and
+        <literal>loadFailure()</literal> callbacks.  The <literal>keycloak.updateToken()</literal> method checks to
         see if the access token hasn't expired.  If it hasn't, and your oauth login returned a refresh token, this method
         will refresh the access token.  Finally, if successful, it will invoke the success callback, which in this case
         is the <literal>loadData()</literal> method.
@@ -136,6 +136,40 @@ keycloak.updateToken(30).success(function() {
         </para>
     </section>
 
+    <section id="javascript-implicit-flow">
+        <title>Implicit and Hybrid Flow</title>
+
+        <para>
+            By default the JavaScript adapter uses <ulink url="http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">OpenID Connect standard (Authorization code) flow</ulink>, which
+            means that after authentication will Keycloak server redirects back to your application and Javascript adapter will exchange <literal>code</literal> for access token and refresh token.
+        </para>
+        <para>
+            However Keycloak also supports <ulink url="http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth">OpenID Connect Implicit flow</ulink>
+            where access token is directly sent after successful authentication from Keycloak and there is no additional request for exchange code.
+            This might have better performance than standard flow as there is no additional request for exchange code-to-token. However sending access token
+            in URL fragment might be security issue in some environments (Token can be more easily stolen from the network etc).
+        </para>
+        <para>To enable implicit flow, you need to enable the flag <literal>Implicit Flow Enabled</literal> for the client in Keycloak admin console. You also need to pass
+            the parameter <literal>flow</literal> with value <literal>implicit</literal> to <literal>init</literal> method, so that Javascript adapter will use implicit flow instead of standard flow.
+            The example is here:
+<programlisting><![CDATA[
+keycloak.init({ flow: 'implicit' })
+]]></programlisting>
+            Note that with implicit flow, you don't have refresh token available after authentication. This makes it harder for your application to periodically update
+            access token in background (without browser redirection). It's recommended that you implement <literal>onTokenExpired</literal> callback method on keycloak object, so you
+            have possibility to do something after token is expired (For example you can call keycloak.login, which will redirect browser to Keycloak login screen and it will immediately
+            redirect you back if SSO session is still valid and user is still logged. However make sure to save the application state before doing redirect.)
+        </para>
+        <para>
+            Keycloak also have support for <ulink url="http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth">OpenID Connect Hybrid flow</ulink>. This requires
+            that client in admin console has both flags <literal>Standard Flow Enabled</literal> and <literal>Implicit Flow Enabled</literal> enabled in admin console.
+            The Keycloak will send both the code and tokens to your application. Access token can be immediately used and in the meantime, code can be exchanged for access token and refresh token.
+            Hybrid flow is good for performance similarly like implicit flow, because access token is available. But similarly like implicit flow, the token is sent in URL fragment, so security may not be so good.
+            In addition to implicit flow, you have also refresh token available in your application. For hybrid flow, you need to pass the parameter
+            <literal>flow</literal> with value <literal>hybrid</literal> to <literal>init</literal> method.
+        </para>
+    </section>
+
     <section>
         <title>Older browsers</title>
 
@@ -178,6 +212,10 @@ new Keycloak({ url: 'http://localhost/auth', realm: 'myrealm', clientId: 'myApp'
                 <listitem>refreshToken - the base64 encoded token that can be used to retrieve a new token</listitem>
                 <listitem>refreshTokenParsed - the parsed refresh token</listitem>
                 <listitem>timeSkew - estimated skew between local time and Keycloak server in seconds</listitem>
+                <listitem>responseMode - responseMode passed during initialization. See below for details. Default value is <literal>fragment</literal></listitem>
+                <listitem>flow - OpenID Connect flow passed during initialization. See <link linkend="javascript-implicit-flow">Implicit flow</link> for details.</listitem>
+                <listitem>responseType - responseType used for send to Keycloak server at login request. This is determined based on the <literal>flow</literal> value used during initialization,
+                    but you have possibility to override it by directly set this value</listitem>
             </itemizedlist>
         </section>
 
@@ -195,6 +233,12 @@ new Keycloak({ url: 'http://localhost/auth', realm: 'myrealm', clientId: 'myApp'
                         <listitem>refreshToken - set an initial value for the refresh token</listitem>
                         <listitem>checkLoginIframe - set to enable/disable monitoring login state (default is true)</listitem>
                         <listitem>checkLoginIframeInterval - set the interval to check login state (default is 5 seconds)</listitem>
+                        <listitem>responseMode - set the OpenID Connect response mode send to Keycloak server at login request. Valid values are <literal>query</literal> or <literal>fragment</literal> .
+                            Default value is <literal>fragment</literal>, which means that after successful authentication will Keycloak redirect to javascript application
+                            with OpenID Connect parameters added in URL fragment. This is generally safer and recommended over <literal>query</literal>.
+                        </listitem>
+                        <listitem>flow - set the OpenID Connect flow. Valid values are <literal>standard</literal>, <literal>implicit</literal> or <literal>hybrid</literal>.
+                            See <link linkend="javascript-implicit-flow">Implicit flow</link> for details.</listitem>
                     </itemizedlist>
                 </para>
                 <para>Returns promise to set functions to be invoked on success or error.</para>
@@ -357,6 +401,7 @@ keycloak.onAuthSuccess = function() { alert('authenticated'); }
                 <listitem>onAuthRefreshSuccess - called when the token is refreshed</listitem>
                 <listitem>onAuthRefreshError - called if there was an error while trying to refresh the token</listitem>
                 <listitem>onAuthLogout - called if the user is logged out (will only be called if the session status iframe is enabled, or in Cordova mode)</listitem>
+                <listitem>onTokenExpired - called when access token expired. When this happens you can for example refresh token, or if refresh not available (ie. with implicit flow) you can redirect to login screen</listitem>
             </itemizedlist>
         </section>
     </section>
diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml b/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml
index 571cd6c..dc0b6a1 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml
@@ -82,12 +82,25 @@
         <section>
             <title>Migrating to 1.7.0.CR1</title>
             <simplesect>
-                <title>Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator</title>
+                <title>Direct access grants disabled by default for clients</title>
                 <para>
-                    form-error-page in web.xml will no longer work for client adapter authentication errors.  You must define an error-page for
-                    the the various HTTP error codes.  See documentation for more details if you want to catch and handle adapter error conditions.
+                    In order to add more compliance with OpenID Connect specification, we added flags into admin console to Client Settings page,
+                    where you can enable/disable various kinds of OpenID Connect/OAuth2 flows (Standard flow, Implicit flow, Direct Access Grants, Service Accounts).
+                    As part of this, we have <literal>Direct Access Grants</literal> (corresponds to OAuth2 <literal>Resource Owner Password Credentials Grant</literal>) disabled by default for new clients.
+                </para>
+                <para>
+                    Clients migrated from previous version have <literal>Direct Access Grants</literal> enabled just if they had flag <literal>Direct Grants Only</literal> on. The
+                    <literal>Direct Grants Only</literal> flag was removed as if you enable Direct Access Grants and disable both Standard+Implicit flow, you will achieve same effect.
                 </para>
                 <para>
+                    We also added builtin client <literal>admin-cli</literal> to each realm. This client has <literal>Direct Access Grants</literal> enabled.
+                    So if you're using Admin REST API or Keycloak admin-client, you should update your configuration to use <literal>admin-cli</literal> instead
+                    of <literal>security-admin-console</literal> as the latter one doesn't have direct access grants enabled anymore by default.
+                </para>
+            </simplesect>
+            <simplesect>
+                <title>Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator</title>
+                <para>
                     In this version, we added <literal>First Broker Login</literal>, which allows you to specify what exactly should be done
                     when new user is logged through Identity provider (or Social provider), but there is no existing Keycloak user
                     yet linked to the social account. As part of this work, we added option <literal>First Login Flow</literal> to identity providers where
@@ -100,6 +113,13 @@
                     and then you configure the option under <literal>Review Profile</literal> authenticator.
                 </para>
             </simplesect>
+            <simplesect>
+                <title>Element 'form-error-page' in web.xml not supported anymore</title>
+                <para>
+                    form-error-page in web.xml will no longer work for client adapter authentication errors.  You must define an error-page for
+                    the various HTTP error codes.  See documentation for more details if you want to catch and handle adapter error conditions.
+                </para>
+            </simplesect>
         </section>
         <section>
             <title>Migrating to 1.6.0.Final</title>
diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/timeouts.xml b/docbook/auth-server-docs/reference/en/en-US/modules/timeouts.xml
index 229ee8d..83983b4 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/timeouts.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/timeouts.xml
@@ -44,9 +44,9 @@
         </para>
         <para>
             The <code class="literal">Access Token Lifespan For Implicit Flow</code> is how long an access token is valid for when using OpenID Connect implicit flow.
-            With implicit flow, there is no refresh token available, so that's why the lifespan is usually bigger than default Access Token Lifespan mentioned above.
+            With implicit flow, there is no refresh token available. That's why the lifespan is usually bigger than default Access Token Lifespan mentioned above.
             See <ulink url="http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth">OpenID Connect specification</ulink> for details about implicit flow and
-            <link linkend="javascript-adapter">Javascript Adapter</link> for some additional details.
+            <link linkend="javascript-adapter">Javascript Adapter</link> for some additional details on how to use it in Keycloak.
         </para>
         <para>
             The <literal>Client login timeout</literal> is how long an access code is valid for.  An access code is obtained
diff --git a/events/api/src/main/java/org/keycloak/events/Details.java b/events/api/src/main/java/org/keycloak/events/Details.java
index a995d7b..ef7f004 100755
--- a/events/api/src/main/java/org/keycloak/events/Details.java
+++ b/events/api/src/main/java/org/keycloak/events/Details.java
@@ -12,6 +12,7 @@ public interface Details {
     String REDIRECT_URI = "redirect_uri";
     String RESPONSE_TYPE = "response_type";
     String RESPONSE_MODE = "response_mode";
+    String GRANT_TYPE = "grant_type";
     String AUTH_TYPE = "auth_type";
     String AUTH_METHOD = "auth_method";
     String IDENTITY_PROVIDER = "identity_provider";
diff --git a/examples/admin-client/example-realm.json b/examples/admin-client/example-realm.json
index 6b0921c..e85bf67 100755
--- a/examples/admin-client/example-realm.json
+++ b/examples/admin-client/example-realm.json
@@ -24,6 +24,7 @@
     "clients": [
         {
             "clientId": "examples-admin-client",
+            "directAccessGrantsEnabled": true,
             "enabled": true,
             "fullScopeAllowed": true,
             "baseUrl": "/examples-admin-client",
diff --git a/examples/basic-auth/basicauthrealm.json b/examples/basic-auth/basicauthrealm.json
index 4ff9d42..13af84f 100644
--- a/examples/basic-auth/basicauthrealm.json
+++ b/examples/basic-auth/basicauthrealm.json
@@ -43,6 +43,8 @@
     "clients": [
         {
             "clientId": "basic-auth-service",
+            "standardFlowEnabled": false,
+            "directAccessGrantsEnabled": true,
             "enabled": true,
             "adminUrl": "/basicauth",
             "baseUrl": "/basicauth",
diff --git a/examples/broker/saml-broker-authentication/saml-broker-realm.json b/examples/broker/saml-broker-authentication/saml-broker-realm.json
old mode 100644
new mode 100755
index 289fa2b..43c8b42
--- a/examples/broker/saml-broker-authentication/saml-broker-realm.json
+++ b/examples/broker/saml-broker-authentication/saml-broker-realm.json
@@ -40,6 +40,8 @@
             "saml.signature.algorithm": "RSA_SHA256",
             "saml.client.signature": "true",
             "saml.authnstatement": "true",
+              "saml_assertion_consumer_url_post": "http://localhost:8080/auth/realms/saml-broker-authentication-realm/broker/saml-identity-provider/endpoint",
+              "saml_single_logout_service_url_post": "http://localhost:8080/auth/realms/saml-broker-authentication-realm/broker/saml-identity-provider/endpoint",
             "saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
             "saml.signing.certificate": "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin"
           }
diff --git a/examples/broker/twitter-authentication/twitter-identity-provider-realm.json b/examples/broker/twitter-authentication/twitter-identity-provider-realm.json
index caae06d..2d9fa73 100644
--- a/examples/broker/twitter-authentication/twitter-identity-provider-realm.json
+++ b/examples/broker/twitter-authentication/twitter-identity-provider-realm.json
@@ -49,6 +49,7 @@
           "enabled": true,
           "fullScopeAllowed": true,
           "baseUrl": "/admin-client",
+          "directAccessGrantsEnabled": true,
           "redirectUris": [
             "/admin-client/*"
           ],
diff --git a/examples/demo-template/testrealm.json b/examples/demo-template/testrealm.json
index 309afdd..2542f82 100755
--- a/examples/demo-template/testrealm.json
+++ b/examples/demo-template/testrealm.json
@@ -178,7 +178,8 @@
             "clientId": "admin-client",
             "enabled": true,
             "publicClient": true,
-            "directGrantsOnly": true
+            "standardFlowEnabled": false,
+            "directAccessGrantsEnabled": true
         },
         {
             "clientId": "product-sa-client",
diff --git a/examples/fuse/testrealm.json b/examples/fuse/testrealm.json
index f7c3754..de93f7d 100644
--- a/examples/fuse/testrealm.json
+++ b/examples/fuse/testrealm.json
@@ -182,7 +182,8 @@
             "clientId": "ssh-jmx-admin-client",
             "enabled": true,
             "publicClient": false,
-            "directGrantsOnly": true,
+            "standardFlowEnabled": false,
+            "directAccessGrantsEnabled": true,
             "secret": "password"
         }
     ],
diff --git a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
index 4980104..f45afb9 100755
--- a/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/account/messages/messages_en.properties
@@ -55,6 +55,7 @@ role_read-token=Read token
 role_offline-access=Offline access
 client_account=Account
 client_security-admin-console=Security Admin Console
+client_admin-cli=Admin CLI
 client_realm-management=Realm Management
 client_broker=Broker
 
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index 11bb11b..4e81a43 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -865,7 +865,6 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se
         $scope.client = {
             enabled: true,
             standardFlowEnabled: true,
-            directAccessGrantsEnabled: true,
             attributes: {}
         };
         $scope.client.attributes['saml_signature_canonicalization_method'] = $scope.canonicalization[0].value;
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index eb54741..5b81a01 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -275,7 +275,7 @@
                 </div>
                 <kc-tooltip>{{:: 'idp-sso-relay-state.tooltip' | translate}}</kc-tooltip>
             </div>
-            <div class="form-group" data-ng-show="!client.bearerOnly && !create && protocol == 'openid-connect'">
+            <div class="form-group" data-ng-show="!client.bearerOnly && !create && protocol == 'openid-connect' && (client.standardFlowEnabled || client.implicitFlowEnabled)">
                 <label class="col-md-2 control-label" for="newWebOrigin">{{:: 'web-origins' | translate}}</label>
 
                 <div class="col-sm-6">
diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
index ffe8328..b1b5890 100644
--- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
@@ -113,6 +113,7 @@ role_read-token=Read token
 role_offline-access=Offline access
 client_account=Account
 client_security-admin-console=Security Admin Console
+client_admin-cli=Admin CLI
 client_realm-management=Realm Management
 client_broker=Broker
 
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java b/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
index 9c8c678..f83e336 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
@@ -1,6 +1,7 @@
 package org.keycloak.migration;
 
 import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
 import org.keycloak.provider.Provider;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 
@@ -21,4 +22,6 @@ public interface MigrationProvider extends Provider {
 
     List<ProtocolMapperModel> getBuiltinMappers(String protocol);
 
+    void setupAdminCli(RealmModel realm);
+
 }
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java
index e4ead4d..2c5710d 100644
--- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java
@@ -2,10 +2,14 @@ package org.keycloak.migration.migrators;
 
 import java.util.List;
 
+import org.keycloak.migration.MigrationProvider;
 import org.keycloak.migration.ModelVersion;
+import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.Constants;
+import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.DefaultAuthenticationFlows;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -17,7 +21,24 @@ public class MigrateTo1_7_0 {
     public void migrate(KeycloakSession session) {
         List<RealmModel> realms = session.realms().getRealms();
         for (RealmModel realm : realms) {
+            // Set default accessToken timeout for implicit flow
             realm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT);
+
+            // Add 'admin-cli' builtin client
+            MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class);
+            migrationProvider.setupAdminCli(realm);
+
+            // add firstBrokerLogin flow and set it to all identityProviders
+            DefaultAuthenticationFlows.migrateFlows(realm);
+            AuthenticationFlowModel firstBrokerLoginFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW);
+
+            List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
+            for (IdentityProviderModel identityProvider : identityProviders) {
+                if (identityProvider.getFirstBrokerLoginFlowId() == null) {
+                    identityProvider.setFirstBrokerLoginFlowId(firstBrokerLoginFlow.getId());
+                    realm.updateIdentityProvider(identityProvider);
+                }
+            }
         }
     }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/Constants.java b/model/api/src/main/java/org/keycloak/models/Constants.java
index c50e4cd..6437cd5 100755
--- a/model/api/src/main/java/org/keycloak/models/Constants.java
+++ b/model/api/src/main/java/org/keycloak/models/Constants.java
@@ -8,6 +8,7 @@ import org.keycloak.OAuth2Constants;
  */
 public interface Constants {
     String ADMIN_CONSOLE_CLIENT_ID = "security-admin-console";
+    String ADMIN_CLI_CLIENT_ID = "admin-cli";
 
     String ACCOUNT_MANAGEMENT_CLIENT_ID = "account";
     String IMPERSONATION_SERVICE_CLIENT_ID = "impersonation";
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 b5edbaf..46259c9 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
@@ -34,7 +34,6 @@ public class ClientEntity extends AbstractIdentifiableEntity {
     private boolean implicitFlowEnabled;
     private boolean directAccessGrantsEnabled;
     private boolean serviceAccountsEnabled;
-    private boolean directGrantsOnly;
     private int nodeReRegistrationTimeout;
 
     // We are using names of defaultRoles (not ids)
@@ -278,14 +277,6 @@ public class ClientEntity extends AbstractIdentifiableEntity {
         this.serviceAccountsEnabled = serviceAccountsEnabled;
     }
 
-    public boolean isDirectGrantsOnly() {
-        return directGrantsOnly;
-    }
-
-    public void setDirectGrantsOnly(boolean directGrantsOnly) {
-        this.directGrantsOnly = directGrantsOnly;
-    }
-
     public List<String> getDefaultRoles() {
         return defaultRoles;
     }
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 8360e48..dfa2e46 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
@@ -460,6 +460,10 @@ public class RepresentationToModel {
             newRealm.setClientAuthenticationFlow(newRealm.getFlowByAlias(rep.getClientAuthenticationFlow()));
         }
 
+        // Added in 1.7
+        if (newRealm.getFlowByAlias(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW) == null) {
+            DefaultAuthenticationFlows.firstBrokerLoginFlow(newRealm, true);
+        }
     }
 
     private static void convertDeprecatedSocialProviders(RealmRepresentation rep) {
@@ -776,17 +780,19 @@ public class RepresentationToModel {
         if (resourceRep.getBaseUrl() != null) client.setBaseUrl(resourceRep.getBaseUrl());
         if (resourceRep.isBearerOnly() != null) client.setBearerOnly(resourceRep.isBearerOnly());
         if (resourceRep.isConsentRequired() != null) client.setConsentRequired(resourceRep.isConsentRequired());
-        if (resourceRep.isStandardFlowEnabled() != null) client.setStandardFlowEnabled(resourceRep.isStandardFlowEnabled());
-        if (resourceRep.isImplicitFlowEnabled() != null) client.setImplicitFlowEnabled(resourceRep.isImplicitFlowEnabled());
-        if (resourceRep.isDirectAccessGrantsEnabled() != null) client.setDirectAccessGrantsEnabled(resourceRep.isDirectAccessGrantsEnabled());
-        if (resourceRep.isServiceAccountsEnabled() != null) client.setServiceAccountsEnabled(resourceRep.isServiceAccountsEnabled());
 
         // Backwards compatibility only
         if (resourceRep.isDirectGrantsOnly() != null) {
             logger.warn("Using deprecated 'directGrantsOnly' configuration in JSON representation. It will be removed in future versions");
             client.setStandardFlowEnabled(!resourceRep.isDirectGrantsOnly());
+            client.setDirectAccessGrantsEnabled(resourceRep.isDirectGrantsOnly());
         }
 
+        if (resourceRep.isStandardFlowEnabled() != null) client.setStandardFlowEnabled(resourceRep.isStandardFlowEnabled());
+        if (resourceRep.isImplicitFlowEnabled() != null) client.setImplicitFlowEnabled(resourceRep.isImplicitFlowEnabled());
+        if (resourceRep.isDirectAccessGrantsEnabled() != null) client.setDirectAccessGrantsEnabled(resourceRep.isDirectAccessGrantsEnabled());
+        if (resourceRep.isServiceAccountsEnabled() != null) client.setServiceAccountsEnabled(resourceRep.isServiceAccountsEnabled());
+
         if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
         if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
         if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
index 60c089b..87fe25b 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
@@ -105,7 +105,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact
                         emailLookup.put(realm, user.getEmail(), user.getId());
                     }
 
-                    log.tracev("User added realm={0}, id={1}, username={2}", realm, event.getValue().getId(), event.getValue().getUsername());
+                    log.tracev("User added realm={0}, id={1}, username={2}", realm, user.getId(), user.getUsername());
                 }
             }
         }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index cb69f14..3f58179 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -726,7 +726,6 @@ public class RealmAdapter implements RealmModel {
         entity.setClientId(clientId);
         entity.setEnabled(true);
         entity.setStandardFlowEnabled(true);
-        entity.setDirectAccessGrantsEnabled(true);
         entity.setRealm(realm);
         realm.getClients().add(entity);
         em.persist(entity);
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index c8fc1f0..fc840ba 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -811,7 +811,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         clientEntity.setRealmId(getId());
         clientEntity.setEnabled(true);
         clientEntity.setStandardFlowEnabled(true);
-        clientEntity.setDirectAccessGrantsEnabled(true);
         getMongoStore().insertEntity(clientEntity, invocationContext);
 
         final ClientModel model = new ClientAdapter(session, this, clientEntity, invocationContext);
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/clientregistration/EntityDescriptorClientRegistrationProvider.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/clientregistration/EntityDescriptorClientRegistrationProvider.java
index 1ee3cd2..10ef019 100644
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/clientregistration/EntityDescriptorClientRegistrationProvider.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/clientregistration/EntityDescriptorClientRegistrationProvider.java
@@ -5,6 +5,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.protocol.saml.EntityDescriptorDescriptionConverter;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.services.clientregistration.AbstractClientRegistrationProvider;
+import org.keycloak.services.clientregistration.ClientRegistrationException;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.POST;
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 3a30c2e..0bc3ede 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -522,7 +522,7 @@ public class SamlProtocol implements LoginProtocol {
         logger.debug("finishLogout");
         String logoutBindingUri = userSession.getNote(SAML_LOGOUT_BINDING_URI);
         if (logoutBindingUri == null) {
-            logger.error("Can't finish SAML logout as there is no logout binding set");
+            logger.error("Can't finish SAML logout as there is no logout binding set.  Please configure the logout service url in the admin console for your client applications.");
             return ErrorPage.error(session, Messages.FAILED_LOGOUT);
 
         }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java
index b4ee957..f4da7e9 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java
@@ -41,13 +41,21 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
             return;
         }
 
-        ExistingUserInfo duplication = checkExistingUser(context, serializedCtx, brokerContext);
+        String username = getUsername(context, serializedCtx, brokerContext);
+        if (username == null) {
+            logger.warnf("%s is null. Reset flow and enforce showing reviewProfile page", realm.isRegistrationEmailAsUsername() ? "Email" : "Username");
+            context.getClientSession().setNote(ENFORCE_UPDATE_PROFILE, "true");
+            context.resetFlow();
+            return;
+        }
+
+        ExistingUserInfo duplication = checkExistingUser(context, username, serializedCtx, brokerContext);
 
         if (duplication == null) {
             logger.debugf("No duplication detected. Creating account for user '%s' and linking with identity provider '%s' .",
-                    brokerContext.getModelUsername(), brokerContext.getIdpConfig().getAlias());
+                    username, brokerContext.getIdpConfig().getAlias());
 
-            UserModel federatedUser = session.users().addUser(realm, brokerContext.getModelUsername());
+            UserModel federatedUser = session.users().addUser(realm, username);
             federatedUser.setEnabled(true);
             federatedUser.setEmail(brokerContext.getEmail());
             federatedUser.setFirstName(brokerContext.getFirstName());
@@ -92,7 +100,7 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
     }
 
     // Could be overriden to detect duplication based on other criterias (firstName, lastName, ...)
-    protected ExistingUserInfo checkExistingUser(AuthenticationFlowContext context, SerializedBrokeredIdentityContext serializedCtx, BrokeredIdentityContext brokerContext) {
+    protected ExistingUserInfo checkExistingUser(AuthenticationFlowContext context, String username, SerializedBrokeredIdentityContext serializedCtx, BrokeredIdentityContext brokerContext) {
 
         if (brokerContext.getEmail() != null) {
             UserModel existingUser = context.getSession().users().getUserByEmail(brokerContext.getEmail(), context.getRealm());
@@ -101,7 +109,7 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
             }
         }
 
-        UserModel existingUser = context.getSession().users().getUserByUsername(brokerContext.getModelUsername(), context.getRealm());
+        UserModel existingUser = context.getSession().users().getUserByUsername(username, context.getRealm());
         if (existingUser != null) {
             return new ExistingUserInfo(existingUser.getId(), UserModel.USERNAME, existingUser.getUsername());
         }
@@ -109,6 +117,11 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
         return null;
     }
 
+    protected String getUsername(AuthenticationFlowContext context, SerializedBrokeredIdentityContext serializedCtx, BrokeredIdentityContext brokerContext) {
+        RealmModel realm = context.getRealm();
+        return realm.isRegistrationEmailAsUsername() ? brokerContext.getEmail() : brokerContext.getModelUsername();
+    }
+
 
     @Override
     public boolean requiresUser() {
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java
index 04eb77b..a4d0ea3 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java
@@ -83,7 +83,7 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
 
         RealmModel realm = context.getRealm();
 
-        List<FormMessage> errors = Validation.validateUpdateProfileForm(true, formData);
+        List<FormMessage> errors = Validation.validateUpdateProfileForm(!realm.isRegistrationEmailAsUsername(), formData);
         if (errors != null && !errors.isEmpty()) {
             Response challenge = context.form()
                     .setErrors(errors)
@@ -94,7 +94,8 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
             return;
         }
 
-        userCtx.setUsername(formData.getFirst(UserModel.USERNAME));
+        String username = realm.isRegistrationEmailAsUsername() ? formData.getFirst(UserModel.EMAIL) : formData.getFirst(UserModel.USERNAME);
+        userCtx.setUsername(username);
         userCtx.setFirstName(formData.getFirst(UserModel.FIRST_NAME));
         userCtx.setLastName(formData.getFirst(UserModel.LAST_NAME));
 
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java
index e10c924..fc472d0 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java
@@ -94,7 +94,8 @@ public class IdpReviewProfileAuthenticatorFactory implements AuthenticatorFactor
         property.setDefaultValue(updateProfileValues);
         property.setHelpText("Define conditions under which a user has to review and update his profile after first-time login. Value 'On' means that"
                 + " page for reviewing profile will be displayed and user can review and update his profile. Value 'off' means that page won't be displayed."
-                + " Value 'missing' means that page is displayed just when some required attribute is missing (wasn't downloaded from identity provider). Value 'missing' is the default one");
+                + " Value 'missing' means that page is displayed just when some required attribute is missing (wasn't downloaded from identity provider). Value 'missing' is the default one."
+                + " WARN: In case that user clicks 'Review profile info' on link duplications page, the update page will be always displayed. You would need to disable this authenticator to never display the page.");
 
         configProperties.add(property);
     }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java
index 8f1b026..7e3990b 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java
@@ -37,13 +37,16 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
     private String code;
     private String token;
 
+    @JsonIgnore
+    private boolean emailAsUsername;
+
     private String identityProviderId;
     private Map<String, ContextDataEntry> contextData = new HashMap<>();
 
     @JsonIgnore
     @Override
     public boolean isEditUsernameAllowed() {
-        return true;
+        return !emailAsUsername;
     }
 
     public String getId() {
@@ -261,6 +264,8 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
         ctx.setToken(context.getToken());
         ctx.setIdentityProviderId(context.getIdpConfig().getAlias());
 
+        ctx.emailAsUsername = context.getClientSession().getRealm().isRegistrationEmailAsUsername();
+
         IdentityProviderDataMarshaller serializer = context.getIdp().getMarshaller();
 
         for (Map.Entry<String, Object> entry : context.getContextData().entrySet()) {
@@ -289,7 +294,9 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
             return null;
         } else {
             try {
-                return JsonSerialization.readValue(asString, SerializedBrokeredIdentityContext.class);
+                SerializedBrokeredIdentityContext serializedCtx = JsonSerialization.readValue(asString, SerializedBrokeredIdentityContext.class);
+                serializedCtx.emailAsUsername = clientSession.getRealm().isRegistrationEmailAsUsername();
+                return serializedCtx;
             } catch (IOException ioe) {
                 throw new RuntimeException(ioe);
             }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index fe358e0..178624b 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -178,6 +178,8 @@ public class TokenEndpoint {
         } else {
             throw new ErrorResponseException(Errors.INVALID_REQUEST, "Invalid " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
         }
+
+        event.detail(Details.GRANT_TYPE, grantType);
     }
 
     public Response buildAuthorizationCodeAccessTokenResponse() {
@@ -223,6 +225,11 @@ public class TokenEndpoint {
             throw new ErrorResponseException("invalid_grant", "Auth error", Response.Status.BAD_REQUEST);
         }
 
+        if (!client.isStandardFlowEnabled()) {
+            event.error(Errors.NOT_ALLOWED);
+            throw new ErrorResponseException("invalid_grant", "Client not allowed to exchange code", Response.Status.BAD_REQUEST);
+        }
+
         UserModel user = session.users().getUserById(userSession.getUser().getId(), realm);
         if (user == null) {
             event.error(Errors.USER_NOT_FOUND);
@@ -327,7 +334,12 @@ public class TokenEndpoint {
     }
 
     public Response buildResourceOwnerPasswordCredentialsGrant() {
-        event.detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD);
+        event.detail(Details.AUTH_METHOD, "oauth_credentials");
+
+        if (!client.isDirectAccessGrantsEnabled()) {
+            event.error(Errors.NOT_ALLOWED);
+            throw new ErrorResponseException("invalid_grant", "Client not allowed for direct access grants", Response.Status.BAD_REQUEST);
+        }
 
         if (client.isConsentRequired()) {
             event.error(Errors.CONSENT_DENIED);
@@ -393,8 +405,6 @@ public class TokenEndpoint {
             throw new ErrorResponseException("unauthorized_client", "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
         }
 
-        event.detail(Details.RESPONSE_TYPE, OAuth2Constants.CLIENT_CREDENTIALS);
-
         UserModel clientUser = session.users().getUserByServiceAccountClient(client);
 
         if (clientUser == null || client.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER) == null) {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
index 60e9f9d..98fb49e 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
@@ -4,6 +4,7 @@ import org.keycloak.OAuth2Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.services.clientregistration.ClientRegistrationService;
 import org.keycloak.services.clientregistration.oidc.OIDCClientRegistrationProviderFactory;
 import org.keycloak.services.resources.RealmsResource;
@@ -22,13 +23,13 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
 
     public static final List<String> DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED = list("RS256");
 
-    public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS);
+    public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS);
 
-    public static final List<String> DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE);
+    public static final List<String> DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE, OIDCResponseType.NONE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token");
 
     public static final List<String> DEFAULT_SUBJECT_TYPES_SUPPORTED = list("public");
 
-    public static final List<String> DEFAULT_RESPONSE_MODES_SUPPORTED = list("query");
+    public static final List<String> DEFAULT_RESPONSE_MODES_SUPPORTED = list("query", "fragment", "form_post");
 
     private KeycloakSession session;
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java
index 06cc3cc..4340229 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java
@@ -42,7 +42,7 @@ public abstract class OIDCRedirectUriBuilder {
 
 
     // http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
-    public static class QueryRedirectUriBuilder extends OIDCRedirectUriBuilder {
+    private static class QueryRedirectUriBuilder extends OIDCRedirectUriBuilder {
 
         protected QueryRedirectUriBuilder(KeycloakUriBuilder uriBuilder) {
             super(uriBuilder);
@@ -64,7 +64,7 @@ public abstract class OIDCRedirectUriBuilder {
 
 
     // http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
-    public static class FragmentRedirectUriBuilder extends OIDCRedirectUriBuilder {
+    private static class FragmentRedirectUriBuilder extends OIDCRedirectUriBuilder {
 
         private StringBuilder fragment;
 
@@ -98,7 +98,7 @@ public abstract class OIDCRedirectUriBuilder {
 
 
     // http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
-    public static class FormPostRedirectUriBuilder extends OIDCRedirectUriBuilder {
+    private static class FormPostRedirectUriBuilder extends OIDCRedirectUriBuilder {
 
         private Map<String, String> params = new HashMap<>();
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java
index 6377b22..9313aa6 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java
@@ -46,6 +46,16 @@ public class OIDCResponseType {
         return new OIDCResponseType(allowedTypes);
     }
 
+    public static OIDCResponseType parse(List<String> responseTypes) {
+        OIDCResponseType result = new OIDCResponseType(new ArrayList<String>());
+        for (String respType : responseTypes) {
+            OIDCResponseType responseType = parse(respType);
+            result.responseTypes.addAll(responseType.responseTypes);
+        }
+
+        return result;
+    }
+
     private static void validateAllowedTypes(List<String> responseTypes) {
         if (responseTypes.size() == 0) {
             throw new IllegalStateException("No responseType provided");
@@ -53,9 +63,6 @@ public class OIDCResponseType {
         if (responseTypes.contains(NONE) && responseTypes.size() > 1) {
             throw new IllegalArgumentException("None not allowed with some other response_type");
         }
-        if (responseTypes.contains(ID_TOKEN) && responseTypes.size() == 1) {
-            throw new IllegalArgumentException("Not supported to use response_type=id_token alone");
-        }
         if (responseTypes.contains(TOKEN) && responseTypes.size() == 1) {
             throw new IllegalArgumentException("Not supported to use response_type=token alone");
         }
@@ -72,7 +79,7 @@ public class OIDCResponseType {
     }
 
     public boolean isImplicitFlow() {
-        return hasResponseType(TOKEN) && hasResponseType(ID_TOKEN) && !hasResponseType(CODE);
+        return hasResponseType(ID_TOKEN) && !hasResponseType(CODE);
     }
 
 
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationException.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationException.java
new file mode 100644
index 0000000..71c9c3d
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationException.java
@@ -0,0 +1,23 @@
+package org.keycloak.services.clientregistration;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegistrationException extends RuntimeException {
+
+    public ClientRegistrationException() {
+        super();
+    }
+
+    public ClientRegistrationException(String message) {
+        super(message);
+    }
+
+    public ClientRegistrationException(Throwable throwable) {
+        super(throwable);
+    }
+
+    public ClientRegistrationException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
index a7f9f2c..594a5f0 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
@@ -1,21 +1,48 @@
 package org.keycloak.services.clientregistration.oidc;
 
+import org.keycloak.OAuth2Constants;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.oidc.OIDCClientRepresentation;
+import org.keycloak.services.clientregistration.ClientRegistrationException;
 
 import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class DescriptionConverter {
 
-    public static ClientRepresentation toInternal(OIDCClientRepresentation clientOIDC) {
+    public static ClientRepresentation toInternal(OIDCClientRepresentation clientOIDC) throws ClientRegistrationException {
         ClientRepresentation client = new ClientRepresentation();
         client.setClientId(clientOIDC.getClientId());
         client.setName(clientOIDC.getClientName());
         client.setRedirectUris(clientOIDC.getRedirectUris());
         client.setBaseUrl(clientOIDC.getClientUri());
+
+        List<String> oidcResponseTypes = clientOIDC.getResponseTypes();
+        if (oidcResponseTypes == null || oidcResponseTypes.isEmpty()) {
+            oidcResponseTypes = Collections.singletonList(OIDCResponseType.CODE);
+        }
+        List<String> oidcGrantTypes = clientOIDC.getGrantTypes();
+
+        try {
+            OIDCResponseType responseType = OIDCResponseType.parse(oidcResponseTypes);
+            client.setStandardFlowEnabled(responseType.hasResponseType(OIDCResponseType.CODE));
+            client.setImplicitFlowEnabled(responseType.isImplicitOrHybridFlow());
+            if (oidcGrantTypes != null) {
+                client.setDirectAccessGrantsEnabled(oidcGrantTypes.contains(OAuth2Constants.PASSWORD));
+                client.setServiceAccountsEnabled(oidcGrantTypes.contains(OAuth2Constants.CLIENT_CREDENTIALS));
+            }
+        } catch (IllegalArgumentException iae) {
+            throw new ClientRegistrationException(iae.getMessage(), iae);
+        }
+
         return client;
     }
 
@@ -28,7 +55,45 @@ public class DescriptionConverter {
         response.setRedirectUris(client.getRedirectUris());
         response.setRegistrationAccessToken(client.getRegistrationAccessToken());
         response.setRegistrationClientUri(uri.toString());
+        response.setResponseTypes(getOIDCResponseTypes(client));
+        response.setGrantTypes(getOIDCGrantTypes(client));
         return response;
     }
 
+    private static List<String> getOIDCResponseTypes(ClientRepresentation client) {
+        List<String> responseTypes = new ArrayList<>();
+        if (client.isStandardFlowEnabled()) {
+            responseTypes.add(OAuth2Constants.CODE);
+            responseTypes.add(OIDCResponseType.NONE);
+        }
+        if (client.isImplicitFlowEnabled()) {
+            responseTypes.add(OIDCResponseType.ID_TOKEN);
+            responseTypes.add("id_token token");
+        }
+        if (client.isStandardFlowEnabled() && client.isImplicitFlowEnabled()) {
+            responseTypes.add("code id_token");
+            responseTypes.add("code token");
+            responseTypes.add("code id_token token");
+        }
+        return responseTypes;
+    }
+
+    private static List<String> getOIDCGrantTypes(ClientRepresentation client) {
+        List<String> grantTypes = new ArrayList<>();
+        if (client.isStandardFlowEnabled()) {
+            grantTypes.add(OAuth2Constants.AUTHORIZATION_CODE);
+        }
+        if (client.isImplicitFlowEnabled()) {
+            grantTypes.add(OAuth2Constants.IMPLICIT);
+        }
+        if (client.isDirectAccessGrantsEnabled()) {
+            grantTypes.add(OAuth2Constants.PASSWORD);
+        }
+        if (client.isServiceAccountsEnabled()) {
+            grantTypes.add(OAuth2Constants.CLIENT_CREDENTIALS);
+        }
+        grantTypes.add(OAuth2Constants.REFRESH_TOKEN);
+        return grantTypes;
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
index e60720b..82b8825 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
@@ -1,5 +1,6 @@
 package org.keycloak.services.clientregistration.oidc;
 
+import org.jboss.logging.Logger;
 import org.keycloak.common.util.Time;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.KeycloakSession;
@@ -9,6 +10,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.clientregistration.AbstractClientRegistrationProvider;
 import org.keycloak.services.clientregistration.ClientRegistrationAuth;
+import org.keycloak.services.clientregistration.ClientRegistrationException;
 import org.keycloak.services.clientregistration.ErrorCodes;
 
 import javax.ws.rs.*;
@@ -21,6 +23,8 @@ import java.net.URI;
  */
 public class OIDCClientRegistrationProvider extends AbstractClientRegistrationProvider {
 
+    private static final Logger log = Logger.getLogger(OIDCClientRegistrationProvider.class);
+
     public OIDCClientRegistrationProvider(KeycloakSession session) {
         super(session);
     }
@@ -33,12 +37,17 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
             throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client Identifier included", Response.Status.BAD_REQUEST);
         }
 
-        ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
-        client = create(client);
-        URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
-        clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
-        clientOIDC.setClientIdIssuedAt(Time.currentTime());
-        return Response.created(uri).entity(clientOIDC).build();
+        try {
+            ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
+            client = create(client);
+            URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
+            clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
+            clientOIDC.setClientIdIssuedAt(Time.currentTime());
+            return Response.created(uri).entity(clientOIDC).build();
+        } catch (ClientRegistrationException cre) {
+            log.error(cre.getMessage());
+            throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client metadata invalid", Response.Status.BAD_REQUEST);
+        }
     }
 
     @GET
@@ -54,11 +63,16 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
     @Path("{clientId}")
     @Consumes(MediaType.APPLICATION_JSON)
     public Response updateOIDC(@PathParam("clientId") String clientId, OIDCClientRepresentation clientOIDC) {
-        ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
-        client = update(clientId, client);
-        URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
-        clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
-        return Response.ok(clientOIDC).build();
+        try {
+            ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
+            client = update(clientId, client);
+            URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
+            clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
+            return Response.ok(clientOIDC).build();
+        } catch (ClientRegistrationException cre) {
+            log.error(cre.getMessage());
+            throw new ErrorResponseException(ErrorCodes.INVALID_CLIENT_METADATA, "Client metadata invalid", Response.Status.BAD_REQUEST);
+        }
     }
 
     @DELETE
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index d44a622..8ab0cfc 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -113,6 +113,7 @@ public class RealmManager implements RealmImporter {
         setupAccountManagement(realm);
         setupBrokerService(realm);
         setupAdminConsole(realm);
+        setupAdminCli(realm);
         setupImpersonationService(realm);
         setupAuthenticationFlows(realm);
         setupRequiredActions(realm);
@@ -158,6 +159,30 @@ public class RealmManager implements RealmImporter {
         adminConsole.addScopeMapping(adminRole);
     }
 
+    public void setupAdminCli(RealmModel realm) {
+        ClientModel adminCli = realm.getClientByClientId(Constants.ADMIN_CLI_CLIENT_ID);
+        if (adminCli == null) {
+            adminCli = new ClientManager(this).createClient(realm, Constants.ADMIN_CLI_CLIENT_ID);
+            adminCli.setName("${client_" + Constants.ADMIN_CLI_CLIENT_ID + "}");
+            adminCli.setEnabled(true);
+            adminCli.setPublicClient(true);
+            adminCli.setFullScopeAllowed(false);
+            adminCli.setStandardFlowEnabled(false);
+            adminCli.setDirectAccessGrantsEnabled(true);
+
+            RoleModel adminRole;
+            if (realm.getName().equals(Config.getAdminRealm())) {
+                adminRole = realm.getRole(AdminRoles.ADMIN);
+            } else {
+                String realmAdminApplicationClientId = getRealmAdminClientId(realm);
+                ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
+                adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
+            }
+            adminCli.addScopeMapping(adminRole);
+        }
+
+    }
+
     public String getRealmAdminClientId(RealmModel realm) {
         return Constants.REALM_MANAGEMENT_CLIENT_ID;
     }
@@ -375,6 +400,16 @@ public class RealmManager implements RealmImporter {
 
         if (!hasBrokerClient(rep)) setupBrokerService(realm);
         if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
+
+        boolean postponeAdminCliSetup = false;
+        if (!hasAdminCliClient(rep)) {
+            if (hasRealmAdminManagementClient(rep)) {
+                postponeAdminCliSetup = true;
+            } else {
+                setupAdminCli(realm);
+            }
+        }
+
         if (!hasRealmRole(rep, Constants.OFFLINE_ACCESS_ROLE)) setupOfflineTokens(realm);
 
         RepresentationToModel.importRealm(session, rep, realm);
@@ -389,6 +424,10 @@ public class RealmManager implements RealmImporter {
             setupImpersonationService(realm);
         }
 
+        if (postponeAdminCliSetup) {
+            setupAdminCli(realm);
+        }
+
         setupAuthenticationFlows(realm);
         setupRequiredActions(realm);
 
@@ -428,6 +467,10 @@ public class RealmManager implements RealmImporter {
         return hasClient(rep, Constants.ADMIN_CONSOLE_CLIENT_ID);
     }
 
+    private boolean hasAdminCliClient(RealmRepresentation rep) {
+        return hasClient(rep, Constants.ADMIN_CLI_CLIENT_ID);
+    }
+
     private boolean hasClient(RealmRepresentation rep, String clientId) {
         if (rep.getClients() != null) {
             for (ClientRepresentation clientRep : rep.getClients()) {
diff --git a/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java b/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java
index ad46afe..e1e6f23 100644
--- a/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java
@@ -10,12 +10,14 @@ import org.keycloak.migration.MigrationProvider;
 import org.keycloak.models.ClaimMask;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.LoginProtocolFactory;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+import org.keycloak.services.managers.RealmManager;
 
 /**
  * Various common utils needed for migration from older version to newer
@@ -60,6 +62,11 @@ public class DefaultMigrationProvider implements MigrationProvider {
     }
 
     @Override
+    public void setupAdminCli(RealmModel realm) {
+        new RealmManager(session).setupAdminCli(realm);
+    }
+
+    @Override
     public void close() {
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 90eab4a..a4d5f27 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -34,6 +34,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.GroupRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.clientregistration.ClientRegistrationException;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.LDAPConnectionTestManager;
 import org.keycloak.services.managers.RealmManager;
diff --git a/services/src/test/java/org/keycloak/test/ResponseTypeTest.java b/services/src/test/java/org/keycloak/test/ResponseTypeTest.java
index b3f77a7..dd15aa9 100644
--- a/services/src/test/java/org/keycloak/test/ResponseTypeTest.java
+++ b/services/src/test/java/org/keycloak/test/ResponseTypeTest.java
@@ -1,5 +1,8 @@
 package org.keycloak.test;
 
+import java.util.Arrays;
+import java.util.Collections;
+
 import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
@@ -16,7 +19,7 @@ public class ResponseTypeTest {
         assertFail("foo");
         assertSuccess("code");
         assertSuccess("none");
-        assertFail("id_token");
+        assertSuccess("id_token");
         assertFail("token");
         assertFail("refresh_token");
         assertSuccess("id_token token");
@@ -27,6 +30,38 @@ public class ResponseTypeTest {
         assertFail("code refresh_token");
     }
 
+    @Test
+    public void testMultipleResponseTypes() {
+        try {
+            OIDCResponseType.parse(Arrays.asList("code", "token"));
+            Assert.fail("Not expected to parse with success");
+        } catch (IllegalArgumentException iae) {
+        }
+
+        OIDCResponseType responseType = OIDCResponseType.parse(Collections.singletonList("code"));
+        Assert.assertTrue(responseType.hasResponseType("code"));
+        Assert.assertFalse(responseType.hasResponseType("none"));
+        Assert.assertFalse(responseType.isImplicitOrHybridFlow());
+
+        responseType = OIDCResponseType.parse(Arrays.asList("code", "none"));
+        Assert.assertTrue(responseType.hasResponseType("code"));
+        Assert.assertTrue(responseType.hasResponseType("none"));
+        Assert.assertFalse(responseType.isImplicitOrHybridFlow());
+
+        responseType = OIDCResponseType.parse(Arrays.asList("code", "code token"));
+        Assert.assertTrue(responseType.hasResponseType("code"));
+        Assert.assertFalse(responseType.hasResponseType("none"));
+        Assert.assertTrue(responseType.hasResponseType("token"));
+        Assert.assertFalse(responseType.hasResponseType("id_token"));
+        Assert.assertTrue(responseType.isImplicitOrHybridFlow());
+        Assert.assertFalse(responseType.isImplicitFlow());
+
+        responseType = OIDCResponseType.parse(Arrays.asList("id_token", "id_token token"));
+        Assert.assertFalse(responseType.hasResponseType("code"));
+        Assert.assertTrue(responseType.isImplicitOrHybridFlow());
+        Assert.assertTrue(responseType.isImplicitFlow());
+    }
+
     private void assertSuccess(String responseType) {
         OIDCResponseType.parse(responseType);
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index 31b0550..1e60096 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -187,7 +187,7 @@ public class AdapterTestStrategy extends ExternalResource {
         Assert.assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
 
         // View stats
-        List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", "security-admin-console").realm("demo").getClientSessionStats();
+        List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID).realm("demo").getClientSessionStats();
         Map<String, String> customerPortalStats = null;
         Map<String, String> productPortalStats = null;
         for (Map<String, String> s : stats) {
@@ -594,7 +594,7 @@ public class AdapterTestStrategy extends ExternalResource {
         loginAndCheckSession(driver, loginPage);
 
         // logout mposolda with admin client
-        Keycloak keycloakAdmin = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID);
+        Keycloak keycloakAdmin = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
         ApiUtil.findClientByClientId(keycloakAdmin.realm("demo"), "session-portal").logoutUser("mposolda");
 
         // bburke should be still logged with original httpSession in our browser window
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
index 6283718..eaebc82 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
@@ -131,7 +131,7 @@ public class RelativeUriAdapterTest {
         Assert.assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
 
         // View stats
-        List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", "security-admin-console").realm("demo").getClientSessionStats();
+        List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID).realm("demo").getClientSessionStats();
         Map<String, String> customerPortalStats = null;
         Map<String, String> productPortalStats = null;
         for (Map<String, String> s : stats) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
index c3f68db..17fa174 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
@@ -43,7 +43,7 @@ public class AddUserTest {
         try {
             server.start();
 
-            Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "addusertest-admin", "password", Constants.ADMIN_CONSOLE_CLIENT_ID);
+            Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "addusertest-admin", "password", Constants.ADMIN_CLI_CLIENT_ID);
             keycloak.realms().findAll();
 
             RealmRepresentation testRealm = new RealmRepresentation();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
index e3d6a57..99edd91 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
@@ -45,10 +45,12 @@ public abstract class AbstractClientTest {
                 testRealm.setEnabled(true);
                 testRealm.setAccessCodeLifespanUserAction(600);
                 KeycloakModelUtils.generateRealmKeys(testRealm);
+
+                appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
             }
         });
 
-        keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID);
+        keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
         realm = keycloak.realm(REALM_NAME);
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
index 8147cb3..e0471df 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
@@ -79,7 +79,7 @@ public class AdminAPITest {
             RealmManager manager = new RealmManager(session);
 
             RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
-            ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
+            ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CLI_CLIENT_ID);
             TokenManager tm = new TokenManager();
             UserModel admin = session.users().getUserByUsername("admin", adminRealm);
             ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index cf2df9d..dd575b1 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -4,6 +4,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.ProtocolMappersResource;
+import org.keycloak.models.Constants;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
@@ -42,7 +43,7 @@ public class ClientTest extends AbstractClientTest {
 
     @Test
     public void getClients() {
-        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker");
+        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID);
     }
 
     private String createClient() {
@@ -60,7 +61,7 @@ public class ClientTest extends AbstractClientTest {
         String id = createClient();
 
         assertNotNull(realm.clients().get(id));
-        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app");
+        assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app", Constants.ADMIN_CLI_CLIENT_ID);
     }
 
     @Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
index 0f1510b..263e4e2 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
@@ -117,7 +117,7 @@ public class ImpersonationTest {
             RealmManager manager = new RealmManager(session);
 
             RealmModel adminRealm = manager.getRealm(realm);
-            ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
+            ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CLI_CLIENT_ID);
             TokenManager tm = new TokenManager();
             UserModel admin = session.users().getUserByUsername(username, adminRealm);
             ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index 84e724b..517f6c3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -135,7 +135,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
         return expect(EventType.CLIENT_LOGIN)
                 .detail(Details.CODE_ID, isCodeId())
                 .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.CLIENT_CREDENTIALS)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS)
                 .removeDetail(Details.CODE_ID)
                 .session(isUUID());
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java
index 7d780cd..36bf4c7 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractFirstBrokerLoginTest.java
@@ -179,6 +179,48 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractIdentityProvi
 
 
     /**
+     * Test user registers with IdentityProvider with emailAsUsername
+     */
+    @Test
+    public void testRegistrationWithEmailAsUsername() {
+        // Require updatePassword after user registered with broker
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_ON);
+                realmWithBroker.setRegistrationEmailAsUsername(true);
+            }
+
+        }, APP_REALM_ID);
+
+        loginIDP("pedroigor");
+        this.updateProfileWithUsernamePage.assertCurrent();
+
+        try {
+            this.updateProfileWithUsernamePage.update("Test", "User", "some-user@redhat.com", "some-user");
+            Assert.fail("It is not expected to see username field");
+        } catch (NoSuchElementException expected) {
+        }
+
+        this.updateProfileWithUsernamePage.update("Test", "User", "some-user@redhat.com");
+
+        // assert authenticated
+        assertFederatedUser("some-user@redhat.com", "some-user@redhat.com", "pedroigor");
+
+        brokerServerRule.update(new KeycloakRule.KeycloakSetup() {
+
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel realmWithBroker) {
+                setUpdateProfileFirstLogin(realmWithBroker, IdentityProviderRepresentation.UPFLM_MISSING);
+                realmWithBroker.setRegistrationEmailAsUsername(false);
+            }
+
+        }, APP_REALM_ID);
+    }
+
+
+    /**
      * Tests that duplication is detected, the confirmation page is displayed, user clicks on "Review profile" and goes back to updateProfile page and resolves duplication
      * by create new user
      */
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
index 1d2e5b6..f88cf0b 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
@@ -267,48 +267,6 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
     }
 
     @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided() {
-
-        getRealm().setRegistrationEmailAsUsername(true);
-        brokerServerRule.stopSession(this.session, true);
-        this.session = brokerServerRule.startSession();
-
-        try {
-            IdentityProviderModel identityProviderModel = getIdentityProviderModel();
-            setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
-
-            authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail", false);
-
-            brokerServerRule.stopSession(session, true);
-            session = brokerServerRule.startSession();
-
-            // check correct user is created with username from provider as email is not available
-            RealmModel realm = getRealm();
-            UserModel federatedUser = getFederatedUser();
-            assertNotNull(federatedUser);
-
-            doAssertFederatedUserNoEmail(federatedUser);
-
-            Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
-
-            assertEquals(1, federatedIdentities.size());
-
-            FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
-
-            assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
-            revokeGrant();
-
-            driver.navigate().to("http://localhost:8081/test-app/logout");
-            driver.navigate().to("http://localhost:8081/test-app");
-
-            assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
-
-        } finally {
-            getRealm().setRegistrationEmailAsUsername(false);
-        }
-    }
-
-    @Test
     public void testDisabled() {
         IdentityProviderModel identityProviderModel = getIdentityProviderModel();
 
@@ -395,6 +353,8 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
     public void testAccountManagementLinkedIdentityAlreadyExists() {
         // Login as "test-user" through broker
         IdentityProviderModel identityProvider = getIdentityProviderModel();
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
         assertSuccessfulAuthentication(identityProvider, "test-user", "test-user@localhost", false);
 
         // Login as pedroigor to account management
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
index 5bfdc1d..63b332b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
@@ -116,11 +116,6 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityP
     }
 
     @Test
-    public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided() {
-        super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided();
-    }
-
-    @Test
     public void testTokenStorageAndRetrievalByApplication() {
         super.testTokenStorageAndRetrievalByApplication();
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
index 11d9a37..b67ffa3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
@@ -77,6 +77,8 @@ public class FederationProvidersIntegrationTest {
             ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
 
             LDAPObject existing = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "existing", "Existing", "Foo", "existing@email.org", null, "5678");
+
+            appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
         }
     });
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
index 4e654aa..4d43897 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
@@ -77,6 +77,8 @@ public class BruteForceTest {
 
             appRealm.setBruteForceProtected(true);
             appRealm.setFailureFactor(2);
+
+            appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
         }
 
     });
@@ -116,7 +118,7 @@ public class BruteForceTest {
     }
 
     public String getAdminToken() throws Exception {
-        String clientId = Constants.ADMIN_CONSOLE_CLIENT_ID;
+        String clientId = Constants.ADMIN_CLI_CLIENT_ID;
         return oauth.doGrantAccessTokenRequest("master", "admin", "admin", null, clientId, null).getAccessToken();
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
index 4690308..31ac261 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
@@ -127,7 +127,11 @@ public class CustomFlowTest {
             // Set passthrough clientAuthenticator for our clients
             ClientModel dummyClient = new ClientManager().createClient(appRealm, "dummy-client");
             dummyClient.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID);
-            appRealm.getClientByClientId("test-app").setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID);
+            dummyClient.setDirectAccessGrantsEnabled(true);
+
+            ClientModel testApp = appRealm.getClientByClientId("test-app");
+            testApp.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID);
+            testApp.setDirectAccessGrantsEnabled(true);
         }
     });
 
@@ -218,7 +222,7 @@ public class CustomFlowTest {
                 .client(clientId)
                 .user(userId)
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .detail(Details.USERNAME, login)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java
index 9f04201..83e14e9 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java
@@ -48,6 +48,7 @@ public class JaxrsBasicAuthTest {
             app.setEnabled(true);
             app.setSecret("password");
             app.setFullScopeAllowed(true);
+            app.setDirectAccessGrantsEnabled(true);
 
             JaxrsBasicAuthTest.appRealm = appRealm;
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
index f2d8b68..646c42b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
@@ -456,7 +456,7 @@ public class SamlAdapterTestStrategy  extends ExternalResource {
 
     public static void uploadSP(String AUTH_SERVER_URL) {
         try {
-            Keycloak keycloak = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID, null);
+            Keycloak keycloak = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID, null);
             RealmResource admin = keycloak.realm("demo");
 
             admin.toRepresentation();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/GroupTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/GroupTest.java
index a5f2388..29ab66b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/GroupTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/GroupTest.java
@@ -62,15 +62,19 @@ public class GroupTest {
         @Override
         public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
             ClientModel app = new ClientManager(manager).createClient(appRealm, "resource-owner");
+            app.setDirectAccessGrantsEnabled(true);
             app.setSecret("secret");
 
+            app = appRealm.getClientByClientId("test-app");
+            app.setDirectAccessGrantsEnabled(true);
+
             UserModel user = session.users().addUser(appRealm, "direct-login");
             user.setEmail("direct-login@localhost");
             user.setEnabled(true);
 
 
             session.users().updateCredential(appRealm, user, UserCredentialModel.password("password"));
-            keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID);
+            keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
         }
     });
 
@@ -257,7 +261,7 @@ public class GroupTest {
                 .client(clientId)
                 .user(userId)
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .detail(Details.USERNAME, login)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index 99e5b95..f016ff0 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -90,7 +90,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertEquals(0,  session.users().getFederatedIdentities(user, realm).size());
 
         List<ClientModel> resources = realm.getClients();
-        Assert.assertEquals(7, resources.size());
+        Assert.assertEquals(8, resources.size());
 
         // Test applications imported
         ClientModel application = realm.getClientByClientId("Application");
@@ -101,7 +101,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertNotNull(otherApp);
         Assert.assertNull(nonExisting);
         Map<String, ClientModel> clients = realm.getClientNameMap();
-        Assert.assertEquals(7, clients.size());
+        Assert.assertEquals(8, clients.size());
         Assert.assertTrue(clients.values().contains(application));
         Assert.assertTrue(clients.values().contains(otherApp));
         Assert.assertTrue(clients.values().contains(accountApp));
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index 1b6cbd6..3f4c53b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -92,7 +92,14 @@ import static org.junit.Assert.*;
 public class AccessTokenTest {
 
     @ClassRule
-    public static KeycloakRule keycloakRule = new KeycloakRule();
+    public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
+        }
+
+    });
 
     @Rule
     public WebRule webRule = new WebRule(this);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
index 898066a..8bc8be8 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
@@ -61,6 +61,7 @@ public class ClientAuthSignedJWTTest {
             app1.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID);
 
             ClientModel app2 = appRealm.addClient("client2");
+            app2.setDirectAccessGrantsEnabled(true);
             new ClientManager(manager).enableServiceAccount(app2);
             app2.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID);
 
@@ -189,7 +190,7 @@ public class ClientAuthSignedJWTTest {
         events.expectLogin()
                 .client("client2")
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .detail(Details.USERNAME, "test-user@localhost")
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
index a4b2855..fab919f 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
@@ -67,6 +67,7 @@ public class OfflineTokenTest {
             appRealm.setSsoSessionIdleTimeout(30);
 
             ClientModel app = new ClientManager(manager).createClient(appRealm, "offline-client");
+            app.setDirectAccessGrantsEnabled(true);
             app.setSecret("secret1");
             String testAppRedirectUri = appRealm.getClientByClientId("test-app").getRedirectUris().iterator().next();
             offlineClientAppUri = UriUtils.getOrigin(testAppRedirectUri) + "/offline-client";
@@ -319,7 +320,7 @@ public class OfflineTokenTest {
                 .client("offline-client")
                 .user(userId)
                 .session(token.getSessionState())
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, token.getId())
                 .detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
                 .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
@@ -361,7 +362,7 @@ public class OfflineTokenTest {
                 .client("offline-client")
                 .user(userId)
                 .session(token.getSessionState())
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, token.getId())
                 .detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
                 .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
index 2373489..a69b733 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
@@ -71,7 +71,14 @@ import static org.junit.Assert.assertNull;
 public class RefreshTokenTest {
 
     @ClassRule
-    public static KeycloakRule keycloakRule = new KeycloakRule();
+    public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
+        }
+
+    });
 
     @Rule
     public WebRule webRule = new WebRule(this);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
index b64a683..edb1bf2 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
@@ -35,9 +35,11 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
         @Override
         public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
             ClientModel app = new ClientManager(manager).createClient(appRealm, "resource-owner");
+            app.setDirectAccessGrantsEnabled(true);
             app.setSecret("secret");
 
             ClientModel app2 = new ClientManager(manager).createClient(appRealm, "resource-owner-public");
+            app2.setDirectAccessGrantsEnabled(true);
             app2.setPublicClient(true);
 
             UserModel user = session.users().addUser(appRealm, "direct-login");
@@ -94,7 +96,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .client(clientId)
                 .user(userId)
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .detail(Details.USERNAME, login)
@@ -130,7 +132,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
         events.expectLogin()
                 .client("resource-owner")
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .removeDetail(Details.CODE_ID)
@@ -192,6 +194,41 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
     }
 
     @Test
+    public void grantAccessTokenClientNotAllowed() throws Exception {
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                ClientModel client = appRealm.getClientByClientId("resource-owner");
+                client.setDirectAccessGrantsEnabled(false);
+            }
+        });
+
+        oauth.clientId("resource-owner");
+
+        OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password");
+
+        assertEquals(400, response.getStatusCode());
+
+        assertEquals("invalid_grant", response.getError());
+
+        events.expectLogin()
+                .client("resource-owner")
+                .session((String) null)
+                .clearDetails()
+                .error(Errors.NOT_ALLOWED)
+                .user((String) null)
+                .assertEvent();
+
+        keycloakRule.update(new KeycloakRule.KeycloakSetup() {
+            @Override
+            public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                ClientModel client = appRealm.getClientByClientId("resource-owner");
+                client.setDirectAccessGrantsEnabled(true);
+            }
+        });
+    }
+
+    @Test
     public void grantAccessTokenVerifyEmail() throws Exception {
 
         keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@@ -286,7 +323,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
         events.expectLogin()
                 .client("resource-owner")
                 .session((String) null)
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
                 .removeDetail(Details.CONSENT)
@@ -308,7 +345,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .client("resource-owner")
                 .user((String) null)
                 .session((String) null)
-                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.USERNAME, "invalid")
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
index 11ced77..6cd8489 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -30,6 +30,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.UserInfo;
+import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
@@ -56,7 +57,14 @@ import static org.junit.Assert.assertNotNull;
 public class UserInfoTest {
 
     @ClassRule
-    public static KeycloakRule keycloakRule = new KeycloakRule();
+    public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
+        }
+
+    });
 
     @Rule
     public WebRule webRule = new WebRule(this);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
index 7878843..446c555 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
@@ -457,7 +457,7 @@ public class SamlBindingTest {
 
     public static void uploadSP() {
         try {
-            Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID, null);
+            Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID, null);
             RealmResource admin = keycloak.realm("demo");
 
             admin.toRepresentation();
diff --git a/testsuite/integration/src/test/resources/adapter-test/demorealm.json b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
index b5cd399..70dc85a 100755
--- a/testsuite/integration/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
@@ -120,6 +120,7 @@
         {
             "name": "customer-portal",
             "enabled": true,
+            "directAccessGrantsEnabled": true,
             "adminUrl": "http://localhost:8081/customer-portal",
             "baseUrl": "http://localhost:8081/customer-portal",
             "redirectUris": [
diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json
index af86592..a08f486 100755
--- a/testsuite/integration/src/test/resources/model/testrealm.json
+++ b/testsuite/integration/src/test/resources/model/testrealm.json
@@ -156,6 +156,7 @@
             "name": "Applicationn",
             "enabled": true,
             "implicitFlowEnabled": true,
+            "directAccessGrantsEnabled": true,
             "nodeReRegistrationTimeout": 50,
             "registeredNodes": {
                 "node1": 10,
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java
index 9b68c43..f1328a9 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/ContainersTestEnricher.java
@@ -183,7 +183,7 @@ public class ContainersTestEnricher {
     private void initializeAdminClient() {
         adminClient.set(Keycloak.getInstance(
                 getAuthServerContextRootFromSystemProperty() + "/auth",
-                MASTER, ADMIN, ADMIN, Constants.ADMIN_CONSOLE_CLIENT_ID));
+                MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID));
     }
 
     private void initializeOAuthClient() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java
index 6278653..37b53c2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientRegistrationTest.java
@@ -104,7 +104,7 @@ public abstract class AbstractClientRegistrationTest extends AbstractKeycloakTes
     }
 
     private String getToken(String username, String password) {
-        return oauthClient.getToken(REALM_NAME, "security-admin-console", null, username, password).getToken();
+        return oauthClient.getToken(REALM_NAME, Constants.ADMIN_CLI_CLIENT_ID, null, username, password).getToken();
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
index 9696274..f0fbe2b 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
@@ -2,12 +2,16 @@ package org.keycloak.testsuite.client;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.keycloak.OAuth2Constants;
 import org.keycloak.client.registration.Auth;
 import org.keycloak.client.registration.ClientRegistrationException;
+import org.keycloak.common.util.CollectionUtil;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
 import org.keycloak.representations.idm.ClientInitialAccessPresentation;
 import org.keycloak.representations.oidc.OIDCClientRepresentation;
 
+import java.util.Arrays;
 import java.util.Collections;
 
 import static org.junit.Assert.*;
@@ -49,6 +53,8 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         assertEquals("http://root", response.getClientUri());
         assertEquals(1, response.getRedirectUris().size());
         assertEquals("http://redirect", response.getRedirectUris().get(0));
+        assertEquals(Arrays.asList("code", "none"), response.getResponseTypes());
+        assertEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN), response.getGrantTypes());
     }
 
     @Test
@@ -59,6 +65,8 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         OIDCClientRepresentation rep = reg.oidc().get(response.getClientId());
         assertNotNull(rep);
         assertNotEquals(response.getRegistrationAccessToken(), rep.getRegistrationAccessToken());
+        assertTrue(CollectionUtil.collectionEquals(Arrays.asList("code", "none"), response.getResponseTypes()));
+        assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN), response.getGrantTypes()));
     }
 
     @Test
@@ -67,11 +75,26 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         reg.auth(Auth.token(response));
 
         response.setRedirectUris(Collections.singletonList("http://newredirect"));
+        response.setResponseTypes(Arrays.asList("code", "id_token token", "code id_token token"));
+        response.setGrantTypes(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD));
 
         OIDCClientRepresentation updated = reg.oidc().update(response);
 
-        assertEquals(1, updated.getRedirectUris().size());
-        assertEquals("http://newredirect", updated.getRedirectUris().get(0));
+        assertTrue(CollectionUtil.collectionEquals(Collections.singletonList("http://newredirect"), updated.getRedirectUris()));
+        assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD), updated.getGrantTypes()));
+        assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.CODE, OIDCResponseType.NONE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token"), updated.getResponseTypes()));
+    }
+
+    @Test
+    public void updateClientError() throws ClientRegistrationException {
+        try {
+            OIDCClientRepresentation response = create();
+            reg.auth(Auth.token(response));
+            response.setResponseTypes(Arrays.asList("code", "token"));
+            reg.oidc().update(response);
+            fail("Not expected to end with success");
+        } catch (ClientRegistrationException cre) {
+        }
     }
 
     @Test
diff --git a/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
index a0ddce4..b0a8888 100755
--- a/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty81/src/test/resources/adapter-test/demorealm.json
@@ -75,6 +75,7 @@
             "enabled": true,
             "adminUrl": "http://localhost:8082/customer-portal",
             "baseUrl": "http://localhost:8082/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8082/customer-portal/*"
             ],
diff --git a/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json b/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json
index d122c19..86e830f 100755
--- a/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json
+++ b/testsuite/jetty/jetty81/src/test/resources/jetty-test/demorealm.json
@@ -46,6 +46,7 @@
             "fullScopeAllowed": true,
             "adminUrl": "http://localhost:8080/customer-portal",
             "baseUrl": "http://localhost:8080/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8080/customer-portal/*"
             ],
diff --git a/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
index a0ddce4..b0a8888 100755
--- a/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty91/src/test/resources/adapter-test/demorealm.json
@@ -75,6 +75,7 @@
             "enabled": true,
             "adminUrl": "http://localhost:8082/customer-portal",
             "baseUrl": "http://localhost:8082/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8082/customer-portal/*"
             ],
diff --git a/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json b/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json
index d122c19..86e830f 100755
--- a/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json
+++ b/testsuite/jetty/jetty91/src/test/resources/jetty-test/demorealm.json
@@ -46,6 +46,7 @@
             "fullScopeAllowed": true,
             "adminUrl": "http://localhost:8080/customer-portal",
             "baseUrl": "http://localhost:8080/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8080/customer-portal/*"
             ],
diff --git a/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
index a0ddce4..b0a8888 100755
--- a/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/jetty/jetty92/src/test/resources/adapter-test/demorealm.json
@@ -75,6 +75,7 @@
             "enabled": true,
             "adminUrl": "http://localhost:8082/customer-portal",
             "baseUrl": "http://localhost:8082/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8082/customer-portal/*"
             ],
diff --git a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
index b577bfa..e8a05f8 100755
--- a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json
@@ -75,6 +75,7 @@
             "enabled": true,
             "adminUrl": "http://localhost:8082/customer-portal",
             "baseUrl": "http://localhost:8082/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8082/customer-portal/*"
             ],
diff --git a/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
index a0ddce4..b0a8888 100755
--- a/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat7/src/test/resources/adapter-test/demorealm.json
@@ -75,6 +75,7 @@
             "enabled": true,
             "adminUrl": "http://localhost:8082/customer-portal",
             "baseUrl": "http://localhost:8082/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8082/customer-portal/*"
             ],
diff --git a/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
index a0ddce4..b0a8888 100755
--- a/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/tomcat8/src/test/resources/adapter-test/demorealm.json
@@ -75,6 +75,7 @@
             "enabled": true,
             "adminUrl": "http://localhost:8082/customer-portal",
             "baseUrl": "http://localhost:8082/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8082/customer-portal/*"
             ],
diff --git a/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json b/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json
index d122c19..86e830f 100755
--- a/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json
+++ b/testsuite/tomcat8/src/test/resources/tomcat-test/demorealm.json
@@ -46,6 +46,7 @@
             "fullScopeAllowed": true,
             "adminUrl": "http://localhost:8080/customer-portal",
             "baseUrl": "http://localhost:8080/customer-portal",
+            "directAccessGrantsEnabled": true,
             "redirectUris": [
                 "http://localhost:8080/customer-portal/*"
             ],