keycloak-aplcache

Merge pull request #1895 from mposolda/master Implicit

11/28/2015 6:02:52 AM

Changes

Details

diff --git a/common/src/main/java/org/keycloak/common/util/KeycloakUriBuilder.java b/common/src/main/java/org/keycloak/common/util/KeycloakUriBuilder.java
index 328916e..35085c7 100755
--- a/common/src/main/java/org/keycloak/common/util/KeycloakUriBuilder.java
+++ b/common/src/main/java/org/keycloak/common/util/KeycloakUriBuilder.java
@@ -342,6 +342,17 @@ public class KeycloakUriBuilder {
     }
 
     /**
+     * Set fragment, but not encode it. It assumes that given fragment was already properly encoded
+     *
+     * @param fragment
+     * @return
+     */
+    public KeycloakUriBuilder encodedFragment(String fragment) {
+        this.fragment = fragment;
+        return this;
+    }
+
+    /**
      * Only replace path params in path of URI.  This changes state of URIBuilder.
      *
      * @param 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 c81b062..eadbdcf 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
@@ -51,6 +51,11 @@
                 <constraints nullable="false"/>
             </column>
         </addColumn>
+
+        <addColumn tableName="REALM">
+            <column name="ACCESS_TOKEN_LIFE_IMPLICIT" type="INT" defaultValueNumeric="0"/>
+        </addColumn>
+
         <dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LGN_MD"/>
 
         <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_GROUP" tableName="KEYCLOAK_GROUP"/>
@@ -69,11 +74,37 @@
         <addUniqueConstraint columnNames="GROUP_ID" constraintName="CON_GROUP_ID_DEF_GROUPS" tableName="REALM_DEFAULT_GROUPS"/>
         <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_DEFAULT_GROUPS" constraintName="FK_DEF_GROUPS_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
         <addForeignKeyConstraint baseColumnNames="GROUP_ID" baseTableName="REALM_DEFAULT_GROUPS" constraintName="FK_DEF_GROUPS_GROUP" referencedColumnNames="ID" referencedTableName="KEYCLOAK_GROUP"/>
+
         <addColumn tableName="CLIENT">
             <column name="REGISTRATION_TOKEN" type="VARCHAR(255)"/>
+            <column name="STANDARD_FLOW_ENABLED" type="BOOLEAN" defaultValueBoolean="true">
+                <constraints nullable="false"/>
+            </column>
+            <column name="IMPLICIT_FLOW_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
+                <constraints nullable="false"/>
+            </column>
+            <column name="DIRECT_ACCESS_GRANTS_ENABLED" type="BOOLEAN" defaultValueBoolean="true">
+                <constraints nullable="false"/>
+            </column>
         </addColumn>
 
+        <update tableName="CLIENT">
+            <column name="STANDARD_FLOW_ENABLED" valueBoolean="false"/>
+            <where>DIRECT_GRANTS_ONLY = :value</where>
+            <whereParams>
+                <param valueBoolean="true" />
+            </whereParams>
+        </update>
+
+        <dropDefaultValue tableName="CLIENT" columnName="DIRECT_GRANTS_ONLY" />
+        <dropColumn tableName="CLIENT" columnName="DIRECT_GRANTS_ONLY"/>
+
         <modifyDataType tableName="REALM" columnName="PASSWORD_POLICY" newDataType="VARCHAR(2550)"/>
 
+        <!-- Sybase specific hacks -->
+        <modifySql dbms="sybase">
+            <regExpReplace replace=".*(SET DEFAULT NULL)" with="SELECT 1" />
+        </modifySql>
+
     </changeSet>
 </databaseChangeLog>
\ No newline at end of file
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
index fa75d6b..e66e16d 100644
--- a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
@@ -28,7 +28,8 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
             Update1_2_0_Beta1.class,
             Update1_2_0_CR1.class,
             Update1_3_0.class,
-            Update1_4_0.class
+            Update1_4_0.class,
+            Update1_7_0.class
     };
 
     @Override
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
new file mode 100644
index 0000000..666a3af
--- /dev/null
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java
@@ -0,0 +1,39 @@
+package org.keycloak.connections.mongo.updater.impl.updates;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class Update1_7_0 extends Update {
+
+    @Override
+    public String getId() {
+        return "1.7.0";
+    }
+
+    @Override
+    public void update(KeycloakSession session) throws ClassNotFoundException {
+        DBCollection clients = db.getCollection("clients");
+        DBCursor clientsCursor = clients.find();
+
+        try {
+            while (clientsCursor.hasNext()) {
+                BasicDBObject client = (BasicDBObject) clientsCursor.next();
+
+                boolean directGrantsOnly = client.getBoolean("directGrantsOnly", false);
+                client.append("standardFlowEnabled", !directGrantsOnly);
+                client.append("implicitFlowEnabled", false);
+                client.append("directAccessGrantsEnabled", true);
+                client.removeField("directGrantsOnly");
+
+                clients.save(client);
+            }
+        } finally {
+            clientsCursor.close();
+        }
+    }
+}
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 514c0fb..aef643c 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
@@ -26,6 +26,9 @@ public class ClientRepresentation {
     protected Integer notBefore;
     protected Boolean bearerOnly;
     protected Boolean consentRequired;
+    protected Boolean standardFlowEnabled;
+    protected Boolean implicitFlowEnabled;
+    protected Boolean directAccessGrantsEnabled;
     protected Boolean serviceAccountsEnabled;
     protected Boolean directGrantsOnly;
     protected Boolean publicClient;
@@ -181,6 +184,30 @@ public class ClientRepresentation {
         this.consentRequired = consentRequired;
     }
 
+    public Boolean isStandardFlowEnabled() {
+        return standardFlowEnabled;
+    }
+
+    public void setStandardFlowEnabled(Boolean standardFlowEnabled) {
+        this.standardFlowEnabled = standardFlowEnabled;
+    }
+
+    public Boolean isImplicitFlowEnabled() {
+        return implicitFlowEnabled;
+    }
+
+    public void setImplicitFlowEnabled(Boolean implicitFlowEnabled) {
+        this.implicitFlowEnabled = implicitFlowEnabled;
+    }
+
+    public Boolean isDirectAccessGrantsEnabled() {
+        return directAccessGrantsEnabled;
+    }
+
+    public void setDirectAccessGrantsEnabled(Boolean directAccessGrantsEnabled) {
+        this.directAccessGrantsEnabled = directAccessGrantsEnabled;
+    }
+
     public Boolean isServiceAccountsEnabled() {
         return serviceAccountsEnabled;
     }
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 989c91d..bc9ebf8 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -12,6 +12,7 @@ public class RealmRepresentation {
     protected Integer notBefore;
     protected Boolean revokeRefreshToken;
     protected Integer accessTokenLifespan;
+    protected Integer accessTokenLifespanForImplicitFlow;
     protected Integer ssoSessionIdleTimeout;
     protected Integer ssoSessionMaxLifespan;
     protected Integer offlineSessionIdleTimeout;
@@ -187,6 +188,14 @@ public class RealmRepresentation {
         this.accessTokenLifespan = accessTokenLifespan;
     }
 
+    public Integer getAccessTokenLifespanForImplicitFlow() {
+        return accessTokenLifespanForImplicitFlow;
+    }
+
+    public void setAccessTokenLifespanForImplicitFlow(Integer accessTokenLifespanForImplicitFlow) {
+        this.accessTokenLifespanForImplicitFlow = accessTokenLifespanForImplicitFlow;
+    }
+
     public Integer getSsoSessionIdleTimeout() {
         return ssoSessionIdleTimeout;
     }
diff --git a/core/src/main/java/org/keycloak/representations/RefreshToken.java b/core/src/main/java/org/keycloak/representations/RefreshToken.java
index 39c7c46..0300673 100755
--- a/core/src/main/java/org/keycloak/representations/RefreshToken.java
+++ b/core/src/main/java/org/keycloak/representations/RefreshToken.java
@@ -28,6 +28,7 @@ public class RefreshToken extends AccessToken {
         this.subject = token.subject;
         this.issuedFor = token.issuedFor;
         this.sessionState = token.sessionState;
+        this.nonce = token.nonce;
         if (token.realmAccess != null) {
             realmAccess = token.realmAccess.clone();
         }
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 7f8800e..229ee8d 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
@@ -43,6 +43,12 @@
             application not knowing if the user's permissions have changed.  This value is usually in minutes.
         </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.
+            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.
+        </para>
+        <para>
             The <literal>Client login timeout</literal> is how long an access code is valid for.  An access code is obtained
             on the 1st leg of the OAuth 2.0 redirection protocol.  This should be a short time limit.  Usually seconds.
         </para>
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 b9c5338..a995d7b 100755
--- a/events/api/src/main/java/org/keycloak/events/Details.java
+++ b/events/api/src/main/java/org/keycloak/events/Details.java
@@ -11,6 +11,7 @@ public interface Details {
     String CODE_ID = "code_id";
     String REDIRECT_URI = "redirect_uri";
     String RESPONSE_TYPE = "response_type";
+    String RESPONSE_MODE = "response_mode";
     String AUTH_TYPE = "auth_type";
     String AUTH_METHOD = "auth_method";
     String IDENTITY_PROVIDER = "identity_provider";
diff --git a/examples/js-console/src/main/webapp/index.html b/examples/js-console/src/main/webapp/index.html
index 2cca0f8..3789a9f 100644
--- a/examples/js-console/src/main/webapp/index.html
+++ b/examples/js-console/src/main/webapp/index.html
@@ -67,8 +67,11 @@
         var o = 'Token Expires:\t\t' + new Date((keycloak.tokenParsed.exp + keycloak.timeSkew) * 1000).toLocaleString() + '\n';
         o += 'Token Expires in:\t' + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds\n';
 
-        o += 'Refresh Token Expires:\t' + new Date((keycloak.refreshTokenParsed.exp + keycloak.timeSkew) * 1000).toLocaleString() + '\n';
-        o += 'Refresh Expires in:\t' + Math.round(keycloak.refreshTokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds';
+        if (keycloak.refreshTokenParsed) {
+            o += 'Refresh Token Expires:\t' + new Date((keycloak.refreshTokenParsed.exp + keycloak.timeSkew) * 1000).toLocaleString() + '\n';
+            o += 'Refresh Expires in:\t' + Math.round(keycloak.refreshTokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds';
+        }
+
         output(o);
     }
 
@@ -106,7 +109,17 @@
         event('Auth Logout');
     };
 
-    keycloak.init().success(function(authenticated) {
+    keycloak.onTokenExpired = function () {
+        event('Access token expired.');
+    };
+
+    // Flow can be changed to 'implicit' or 'hybrid', but then client must enable implicit flow in admin console too 
+    var initOptions = {
+        responseMode: 'fragment',
+        flow: 'standard'
+    };
+
+    keycloak.init(initOptions).success(function(authenticated) {
         output('Init Success (' + (authenticated ? 'Authenticated' : 'Not Authenticated') + ')');
     }).error(function() {
         output('Init Error');
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index bf1af10..b92f65b 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -80,6 +80,8 @@ offline-session-idle=Offline Session Idle
 offline-session-idle.tooltip=Time an offline session is allowed to be idle before it expires. You need to use offline token to refresh at least once within this period, otherwise offline session will expire.
 access-token-lifespan=Access Token Lifespan
 access-token-lifespan.tooltip=Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout.
+access-token-lifespan-for-implicit-flow=Access Token Lifespan For Implicit Flow
+access-token-lifespan-for-implicit-flow.tooltip=Max time before an access token issued during OpenID Connect Implicit Flow is expired. This value is recommended to be shorter than SSO timeout. There is no possibility to refresh token during implicit flow, that's why there is separate timeout different to 'Access Token Lifespan'.
 client-login-timeout=Client login timeout
 client-login-timeout.tooltip=Max time an client has to finish the access token protocol. This should normally be 1 minute.
 login-timeout=Login timeout
@@ -169,14 +171,18 @@ client.name.tooltip=Specifies display name of the client. For example 'My Client
 client.enabled.tooltip=Disabled clients cannot initiate a login or have obtain access tokens.
 consent-required=Consent Required
 consent-required.tooltip=If enabled users have to consent to client access.
-direct-grants-only=Direct Grants Only
-direct-grants-only.tooltip=When enabled, client can only obtain grants from grant REST API.
 client-protocol=Client Protocol
 client-protocol.tooltip='OpenID connect' allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server.'SAML' enables web-based authentication and authorization scenarios including cross-domain single sign-on (SSO) and uses security tokens containing assertions to pass information.
 access-type=Access Type
 access-type.tooltip='Confidential' clients require a secret to initiate login protocol.  'Public' clients do not require a secret.  'Bearer-only' clients are web services that never initiate a login.
+standard-flow-enabled=Standard Flow Enabled
+standard-flow-enabled.tooltip=This enables standard OpenID Connect redirect based authentication with authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Authorization Code Flow' for this client.
+implicit-flow-enabled=Implicit Flow Enabled
+implicit-flow-enabled.tooltip=This enables support for OpenID Connect redirect based authentication without authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Implicit Flow' for this client.
+direct-access-grants-enabled=Direct Access Grants Enabled
+direct-access-grants-enabled.tooltip=This enables support for Direct Access Grants, which means that client has access to username/password of user and exchange it directly with Keycloak server for access token. In terms of OAuth2 specification, this enables support of 'Resource Owner Password Credentials Grant' for this client.
 service-accounts-enabled=Service Accounts Enabled
-service-accounts-enabled.tooltip=Allows you to authenticate this client to Keycloak and retrieve access token dedicated to this client.
+service-accounts-enabled.tooltip=Allows you to authenticate this client to Keycloak and retrieve access token dedicated to this client. In terms of OAuth2 specification, this enables support of 'Client Credentials Grant' for this client.
 include-authnstatement=Include AuthnStatement
 include-authnstatement.tooltip=Should a statement specifying the method and timestamp be included in login responses?
 sign-documents=Sign Documents
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 2f3ef63..11bb11b 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
@@ -862,7 +862,12 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se
         $scope.client = angular.copy(client);
         updateProperties();
     } else {
-        $scope.client = { enabled: true, attributes: {}};
+        $scope.client = {
+            enabled: true,
+            standardFlowEnabled: true,
+            directAccessGrantsEnabled: true,
+            attributes: {}
+        };
         $scope.client.attributes['saml_signature_canonicalization_method'] = $scope.canonicalization[0].value;
         $scope.client.redirectUris = [];
         $scope.accessType = $scope.accessTypes[0];
@@ -1039,7 +1044,7 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se
         $scope.client.attributes['saml.signature.algorithm'] = $scope.signatureAlgorithm;
         $scope.client.attributes['saml_name_id_format'] = $scope.nameIdFormat;
 
-        if ($scope.client.protocol != 'saml' && !$scope.client.bearerOnly && !$scope.client.directGrantsOnly && (!$scope.client.redirectUris || $scope.client.redirectUris.length == 0)) {
+        if ($scope.client.protocol != 'saml' && !$scope.client.bearerOnly && ($scope.client.standardFlowEnabled || $scope.client.implicitFlowEnabled) && (!$scope.client.redirectUris || $scope.client.redirectUris.length == 0)) {
             Notifications.error("You must specify at least one redirect uri");
         } else {
             if ($scope.create) {
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index b2c7848..a66e205 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -899,6 +899,12 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, 
         $scope.realm.accessTokenLifespan = TimeUnit.convert($scope.realm.accessTokenLifespan, from, to);
     });
 
+    $scope.realm.accessTokenLifespanForImplicitFlowUnit = TimeUnit.autoUnit(realm.accessTokenLifespanForImplicitFlow);
+    $scope.realm.accessTokenLifespanForImplicitFlow = TimeUnit.toUnit(realm.accessTokenLifespanForImplicitFlow, $scope.realm.accessTokenLifespanForImplicitFlowUnit);
+    $scope.$watch('realm.accessTokenLifespanForImplicitFlowUnit', function(to, from) {
+        $scope.realm.accessTokenLifespanForImplicitFlow = TimeUnit.convert($scope.realm.accessTokenLifespanForImplicitFlow, from, to);
+    });
+
     $scope.realm.ssoSessionIdleTimeoutUnit = TimeUnit.autoUnit(realm.ssoSessionIdleTimeout);
     $scope.realm.ssoSessionIdleTimeout = TimeUnit.toUnit(realm.ssoSessionIdleTimeout, $scope.realm.ssoSessionIdleTimeoutUnit);
     $scope.$watch('realm.ssoSessionIdleTimeoutUnit', function(to, from) {
@@ -947,6 +953,7 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, 
     $scope.save = function() {
         var realmCopy = angular.copy($scope.realm);
         delete realmCopy["accessTokenLifespanUnit"];
+        delete realmCopy["accessTokenLifespanForImplicitFlowUnit"];
         delete realmCopy["ssoSessionMaxLifespanUnit"];
         delete realmCopy["offlineSessionIdleTimeoutUnit"];
         delete realmCopy["accessCodeLifespanUnit"];
@@ -955,6 +962,7 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, 
         delete realmCopy["accessCodeLifespanLoginUnit"];
 
         realmCopy.accessTokenLifespan = TimeUnit.toSeconds($scope.realm.accessTokenLifespan, $scope.realm.accessTokenLifespanUnit)
+        realmCopy.accessTokenLifespanForImplicitFlow = TimeUnit.toSeconds($scope.realm.accessTokenLifespanForImplicitFlow, $scope.realm.accessTokenLifespanForImplicitFlowUnit)
         realmCopy.ssoSessionIdleTimeout = TimeUnit.toSeconds($scope.realm.ssoSessionIdleTimeout, $scope.realm.ssoSessionIdleTimeoutUnit)
         realmCopy.ssoSessionMaxLifespan = TimeUnit.toSeconds($scope.realm.ssoSessionMaxLifespan, $scope.realm.ssoSessionMaxLifespanUnit)
         realmCopy.offlineSessionIdleTimeout = TimeUnit.toSeconds($scope.realm.offlineSessionIdleTimeout, $scope.realm.offlineSessionIdleTimeoutUnit)
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 443cbe9..eb54741 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
@@ -59,13 +59,6 @@
                 </div>
                 <kc-tooltip>{{:: 'consent-required.tooltip' | translate}}</kc-tooltip>
             </div>
-            <div class="form-group clearfix block">
-                <label class="col-md-2 control-label" for="directGrantsOnly">{{:: 'direct-grants-only' | translate}}</label>
-                <div class="col-sm-6">
-                    <input ng-model="client.directGrantsOnly" name="directGrantsOnly" id="directGrantsOnly" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
-                </div>
-                <kc-tooltip>{{:: 'direct-grants-only.tooltip' | translate}}</kc-tooltip>
-            </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="protocol">{{:: 'client-protocol' | translate}}</label>
                 <div class="col-sm-6">
@@ -92,6 +85,27 @@
                 </div>
                 <kc-tooltip>{{:: 'access-type.tooltip' | translate}}</kc-tooltip>
             </div>
+            <div class="form-group" data-ng-show="protocol == 'openid-connect' && !client.bearerOnly">
+                <label class="col-md-2 control-label" for="standardFlowEnabled">{{:: 'standard-flow-enabled' | translate}}</label>
+                <kc-tooltip>{{:: 'standard-flow-enabled.tooltip' | translate}}</kc-tooltip>
+                <div class="col-md-6">
+                    <input ng-model="client.standardFlowEnabled" name="standardFlowEnabled" id="standardFlowEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+                </div>
+            </div>
+            <div class="form-group" data-ng-show="protocol == 'openid-connect' && client.publicClient && !client.bearerOnly">
+                <label class="col-md-2 control-label" for="implicitFlowEnabled">{{:: 'implicit-flow-enabled' | translate}}</label>
+                <kc-tooltip>{{:: 'implicit-flow-enabled.tooltip' | translate}}</kc-tooltip>
+                <div class="col-md-6">
+                    <input ng-model="client.implicitFlowEnabled" name="implicitFlowEnabled" id="implicitFlowEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+                </div>
+            </div>
+            <div class="form-group" data-ng-show="protocol == 'openid-connect' && !client.bearerOnly">
+                <label class="col-md-2 control-label" for="directAccessGrantsEnabled">{{:: 'direct-access-grants-enabled' | translate}}</label>
+                <kc-tooltip>{{:: 'direct-access-grants-enabled.tooltip' | translate}}</kc-tooltip>
+                <div class="col-md-6">
+                    <input ng-model="client.directAccessGrantsEnabled" name="directAccessGrantsEnabled" id="directAccessGrantsEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+                </div>
+            </div>
             <div class="form-group" data-ng-show="protocol == 'openid-connect' && !client.publicClient && !client.bearerOnly">
                 <label class="col-md-2 control-label" for="serviceAccountsEnabled">{{:: 'service-accounts-enabled' | translate}}</label>
                 <kc-tooltip>{{:: 'service-accounts-enabled.tooltip' | translate}}</kc-tooltip>
@@ -202,7 +216,7 @@
                 <kc-tooltip>{{:: 'root-url.tooltip' | translate}}</kc-tooltip>
             </div>
 
-            <div class="form-group clearfix block" data-ng-hide="client.bearerOnly || client.directGrantsOnly">
+            <div class="form-group clearfix block" data-ng-hide="client.bearerOnly || (!client.standardFlowEnabled && !client.implicitFlowEnabled)">
                 <label class="col-md-2 control-label" for="newRedirectUri"><span class="required" data-ng-show="protocol != 'saml'">*</span> {{:: 'valid-redirect-uris' | translate}}</label>
 
                 <div class="col-sm-6">
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-tokens.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-tokens.html
index dee13f6..bdfd390 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-tokens.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-tokens.html
@@ -83,6 +83,23 @@
         </div>
 
         <div class="form-group">
+            <label class="col-md-2 control-label" for="accessTokenLifespanForImplicitFlow">{{:: 'access-token-lifespan-for-implicit-flow' | translate}}</label>
+
+            <div class="col-md-6 time-selector">
+                <input class="form-control" type="number" required min="1"
+                       max="31536000" data-ng-model="realm.accessTokenLifespanForImplicitFlow"
+                       id="accessTokenLifespanForImplicitFlow" name="accessTokenLifespanForImplicitFlow"/>
+                <select class="form-control" name="accessTokenLifespanForImplicitFlowUnit" data-ng-model="realm.accessTokenLifespanForImplicitFlowUnit">
+                    <option data-ng-selected="!realm.accessTokenLifespanForImplicitFlowUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
+                    <option value="Minutes">{{:: 'minutes' | translate}}</option>
+                    <option value="Hours">{{:: 'hours' | translate}}</option>
+                    <option value="Days">{{:: 'days' | translate}}</option>
+                </select>
+            </div>
+            <kc-tooltip>{{:: 'access-token-lifespan-for-implicit-flow.tooltip' | translate}}</kc-tooltip>
+        </div>
+
+        <div class="form-group">
             <label class="col-md-2 control-label" for="accessCodeLifespan">{{:: 'client-login-timeout' | translate}}</label>
 
             <div class="col-md-6 time-selector">
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 6885308..ffe8328 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
@@ -176,7 +176,8 @@ failedLogout=Logout failed
 unknownLoginRequesterMessage=Unknown login requester
 loginRequesterNotEnabledMessage=Login requester not enabled
 bearerOnlyMessage=Bearer-only applications are not allowed to initiate browser login
-directGrantsOnlyMessage=Direct-grants-only clients are not allowed to initiate browser login
+standardFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.
+implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.
 invalidRedirectUriMessage=Invalid redirect uri
 unsupportedNameIdFormatMessage=Unsupported NameIDFormat
 invlidRequesterMessage=Invalid requester
diff --git a/integration/js/src/main/resources/keycloak.js b/integration/js/src/main/resources/keycloak.js
index 09e0d86..a74e1cc 100755
--- a/integration/js/src/main/resources/keycloak.js
+++ b/integration/js/src/main/resources/keycloak.js
@@ -36,6 +36,39 @@
                 if (initOptions.onLoad === 'login-required') {
                     kc.loginRequired = true;
                 }
+
+                if (initOptions.responseMode) {
+                    if (initOptions.responseMode === 'query' || initOptions.responseMode === 'fragment') {
+                        kc.responseMode = initOptions.responseMode;
+                    } else {
+                        throw 'Invalid value for responseMode';
+                    }
+                }
+
+                if (initOptions.flow) {
+                    switch (initOptions.flow) {
+                        case 'standard':
+                            kc.responseType = 'code';
+                            break;
+                        case 'implicit':
+                            kc.responseType = 'id_token token';
+                            break;
+                        case 'hybrid':
+                            kc.responseType = 'code id_token token';
+                            break;
+                        default:
+                            throw 'Invalid value for flow';
+                    }
+                    kc.flow = initOptions.flow;
+                }
+            }
+
+            if (!kc.responseMode) {
+                kc.responseMode = 'fragment';
+            }
+            if (!kc.responseType) {
+                kc.responseType = 'code';
+                kc.flow = 'standard';
             }
 
             var promise = createPromise();
@@ -95,7 +128,7 @@
                     return;
                 } else if (initOptions) {
                     if (initOptions.token || initOptions.refreshToken) {
-                        setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
+                        setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken, false);
 
                         if (loginIframe.enable) {
                             setupCheckLoginIframe().success(function() {
@@ -132,13 +165,14 @@
 
         kc.createLoginUrl = function(options) {
             var state = createUUID();
+            var nonce = createUUID();
 
             var redirectUri = adapter.redirectUri(options);
             if (options && options.prompt) {
                 redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'prompt=' + options.prompt;
             }
 
-            sessionStorage.oauthState = JSON.stringify({ state: state, redirectUri: encodeURIComponent(redirectUri) });
+            sessionStorage.oauthState = JSON.stringify({ state: state, nonce: nonce, redirectUri: encodeURIComponent(redirectUri) });
 
             var action = 'auth';
             if (options && options.action == 'register') {
@@ -150,7 +184,9 @@
                 + '?client_id=' + encodeURIComponent(kc.clientId)
                 + '&redirect_uri=' + encodeURIComponent(redirectUri)
                 + '&state=' + encodeURIComponent(state)
-                + '&response_type=code';
+                + '&nonce=' + encodeURIComponent(nonce)
+                + '&response_mode=' + encodeURIComponent(kc.responseMode)
+                + '&response_type=' + encodeURIComponent(kc.responseType);
 
             if (options && options.prompt) {
                 url += '&prompt=' + encodeURIComponent(options.prompt);
@@ -277,7 +313,7 @@
         }
 
         kc.isTokenExpired = function(minValidity) {
-            if (!kc.tokenParsed || !kc.refreshToken) {
+            if (!kc.tokenParsed || (!kc.refreshToken && kc.flow != 'implicit' )) {
                 throw 'Not authenticated';
             }
 
@@ -327,7 +363,7 @@
                                     timeLocal = (timeLocal + new Date().getTime()) / 2;
 
                                     var tokenResponse = JSON.parse(req.responseText);
-                                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
+                                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], true);
 
                                     kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
 
@@ -365,7 +401,7 @@
 
         kc.clearToken = function() {
             if (kc.token) {
-                setToken(null, null, null);
+                setToken(null, null, null, true);
                 kc.onAuthLogout && kc.onAuthLogout();
                 if (kc.loginRequired) {
                     kc.login();
@@ -394,7 +430,21 @@
             var error = oauth.error;
             var prompt = oauth.prompt;
 
-            if (code) {
+            var timeLocal = new Date().getTime();
+
+            if (error) {
+                if (prompt != 'none') {
+                    kc.onAuthError && kc.onAuthError();
+                    promise && promise.setError();
+                } else {
+                    promise && promise.setSuccess();
+                }
+                return;
+            } else if ((kc.flow != 'standard') && (oauth.access_token || oauth.id_token)) {
+                authSuccess(oauth.access_token, null, oauth.id_token, true);
+            }
+
+            if ((kc.flow != 'implicit') && code) {
                 var params = 'code=' + code + '&grant_type=authorization_code';
                 var url = getRealmUrl() + '/protocol/openid-connect/token';
 
@@ -412,20 +462,12 @@
 
                 req.withCredentials = true;
 
-                var timeLocal = new Date().getTime();
-
                 req.onreadystatechange = function() {
                     if (req.readyState == 4) {
                         if (req.status == 200) {
-                            timeLocal = (timeLocal + new Date().getTime()) / 2;
 
                             var tokenResponse = JSON.parse(req.responseText);
-                            setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
-
-                            kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
-
-                            kc.onAuthSuccess && kc.onAuthSuccess();
-                            promise && promise.setSuccess();
+                            authSuccess(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], kc.flow === 'standard');
                         } else {
                             kc.onAuthError && kc.onAuthError();
                             promise && promise.setError();
@@ -434,14 +476,30 @@
                 };
 
                 req.send(params);
-            } else if (error) {
-                if (prompt != 'none') {
-                    kc.onAuthError && kc.onAuthError();
+            }
+
+            function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
+                timeLocal = (timeLocal + new Date().getTime()) / 2;
+
+                setToken(accessToken, refreshToken, idToken, true);
+
+                if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
+                    (kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
+                    (kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce)) {
+
+                    console.log('invalid nonce!');
+                    kc.clearToken();
                     promise && promise.setError();
                 } else {
-                    promise && promise.setSuccess();
+                    kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
+
+                    if (fulfillPromise) {
+                        kc.onAuthSuccess && kc.onAuthSuccess();
+                        promise && promise.setSuccess();
+                    }
                 }
             }
+
         }
 
         function loadConfig(url) {
@@ -507,7 +565,12 @@
             return promise.promise;
         }
 
-        function setToken(token, refreshToken, idToken) {
+        function setToken(token, refreshToken, idToken, useTokenTime) {
+            if (kc.tokenTimeoutHandle) {
+                clearTimeout(kc.tokenTimeoutHandle);
+                kc.tokenTimeoutHandle = null;
+            }
+
             if (token) {
                 kc.token = token;
                 kc.tokenParsed = decodeToken(token);
@@ -520,6 +583,13 @@
                 kc.subject = kc.tokenParsed.sub;
                 kc.realmAccess = kc.tokenParsed.realm_access;
                 kc.resourceAccess = kc.tokenParsed.resource_access;
+
+                if (kc.onTokenExpired) {
+                    var start = useTokenTime ? kc.tokenParsed.iat : (new Date().getTime() / 1000);
+                    var expiresIn = kc.tokenParsed.exp - start;
+                    kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn * 1000);
+                }
+
             } else {
                 delete kc.token;
                 delete kc.tokenParsed;
@@ -597,53 +667,21 @@
         }
 
         function parseCallback(url) {
-            if (url.indexOf('?') != -1) {
-                var oauth = {};
+            var oauth = new CallbackParser(url, kc.responseMode).parseUri();
 
-                oauth.newUrl = url.split('?')[0];
-                var paramString = url.split('?')[1];
-                var fragIndex = paramString.indexOf('#');
-                if (fragIndex != -1) {
-                    paramString = paramString.substring(0, fragIndex);
-                }
-                var params = paramString.split('&');
-                for (var i = 0; i < params.length; i++) {
-                    var p = params[i].split('=');
-                    switch (decodeURIComponent(p[0])) {
-                        case 'code':
-                            oauth.code = p[1];
-                            break;
-                        case 'error':
-                            oauth.error = p[1];
-                            break;
-                        case 'state':
-                            oauth.state = decodeURIComponent(p[1]);
-                            break;
-                        case 'redirect_fragment':
-                            oauth.fragment = decodeURIComponent(p[1]);
-                            break;
-                        case 'prompt':
-                            oauth.prompt = p[1];
-                            break;
-                        default:
-                            oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + p[0] + '=' + p[1];
-                            break;
-                    }
-                }
-
-                var sessionState = sessionStorage.oauthState && JSON.parse(sessionStorage.oauthState);
+            var sessionState = sessionStorage.oauthState && JSON.parse(sessionStorage.oauthState);
 
-                if (sessionState && (oauth.code || oauth.error) && oauth.state && oauth.state == sessionState.state) {
-                    delete sessionStorage.oauthState;
+            if (sessionState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token) && oauth.state && oauth.state == sessionState.state) {
+                delete sessionStorage.oauthState;
 
-                    oauth.redirectUri = sessionState.redirectUri;
+                oauth.redirectUri = sessionState.redirectUri;
+                oauth.storedNonce = sessionState.nonce;
 
-                    if (oauth.fragment) {
-                        oauth.newUrl += '#' + oauth.fragment;
-                    }
-
-                    return oauth;
+                if (oauth.fragment) {
+                    oauth.newUrl += '#' + oauth.fragment;
                 }
+
+                return oauth;
             }
         }
 
@@ -907,6 +945,103 @@
 
             throw 'invalid adapter type: ' + type;
         }
+
+
+        var CallbackParser = function(uriToParse, responseMode) {
+            if (!(this instanceof CallbackParser)) {
+                return new CallbackParser(uriToParse, responseMode);
+            }
+            var parser = this;
+
+            var initialParse = function() {
+                var baseUri = null;
+                var queryString = null;
+                var fragmentString = null;
+
+                var questionMarkIndex = uriToParse.indexOf("?");
+                var fragmentIndex = uriToParse.indexOf("#", questionMarkIndex + 1);
+                if (questionMarkIndex == -1 && fragmentIndex == -1) {
+                    baseUri = uriToParse;
+                } else if (questionMarkIndex != -1) {
+                    baseUri = uriToParse.substring(0, questionMarkIndex);
+                    queryString = uriToParse.substring(questionMarkIndex + 1);
+                    if (fragmentIndex != -1) {
+                        fragmentIndex = queryString.indexOf("#");
+                        fragmentString = queryString.substring(fragmentIndex + 1);
+                        queryString = queryString.substring(0, fragmentIndex);
+                    }
+                } else {
+                    baseUri = uriToParse.substring(0, fragmentIndex);
+                    fragmentString = uriToParse.substring(fragmentIndex + 1);
+                }
+
+                return { baseUri: baseUri, queryString: queryString, fragmentString: fragmentString };
+            }
+
+            var parseParams = function(paramString) {
+                var result = {};
+                var params = paramString.split('&');
+                for (var i = 0; i < params.length; i++) {
+                    var p = params[i].split('=');
+                    var paramName = decodeURIComponent(p[0]);
+                    var paramValue = decodeURIComponent(p[1]);
+                    result[paramName] = paramValue;
+                }
+                return result;
+            }
+
+            var handleQueryParam = function(paramName, paramValue, oauth) {
+                var supportedOAuthParams = [ 'code', 'error', 'state' ];
+
+                for (var i = 0 ; i< supportedOAuthParams.length ; i++) {
+                    if (paramName === supportedOAuthParams[i]) {
+                        oauth[paramName] = paramValue;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+
+            parser.parseUri = function() {
+                var parsedUri = initialParse();
+
+                var queryParams = {};
+                if (parsedUri.queryString) {
+                    queryParams = parseParams(parsedUri.queryString);
+                }
+
+                var oauth = { newUrl: parsedUri.baseUri };
+                for (var param in queryParams) {
+                    switch (param) {
+                        case 'redirect_fragment':
+                            oauth.fragment = queryParams[param];
+                            break;
+                        case 'prompt':
+                            oauth.prompt = queryParams[param];
+                            break;
+                        default:
+                            if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
+                                oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + queryParams[param];
+                            }
+                            break;
+                    }
+                }
+
+                if (responseMode === 'fragment') {
+                    var fragmentParams = {};
+                    if (parsedUri.fragmentString) {
+                        fragmentParams = parseParams(parsedUri.fragmentString);
+                    }
+                    for (var param in fragmentParams) {
+                        oauth[param] = fragmentParams[param];
+                    }
+                }
+
+                return oauth;
+            }
+        }
+
     }
 
     if ( typeof module === "object" && module && typeof module.exports === "object" ) {
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
index e5c9484..06df073 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationModelManager.java
@@ -5,6 +5,7 @@ import org.keycloak.migration.migrators.MigrateTo1_3_0;
 import org.keycloak.migration.migrators.MigrateTo1_4_0;
 import org.keycloak.migration.migrators.MigrateTo1_5_0;
 import org.keycloak.migration.migrators.MigrateTo1_6_0;
+import org.keycloak.migration.migrators.MigrateTo1_7_0;
 import org.keycloak.migration.migrators.MigrationTo1_2_0_CR1;
 import org.keycloak.models.KeycloakSession;
 
@@ -54,6 +55,12 @@ public class MigrationModelManager {
             }
             new MigrateTo1_6_0().migrate(session);
         }
+        if (stored == null || stored.lessThan(MigrateTo1_7_0.VERSION)) {
+            if (stored != null) {
+                logger.debug("Migrating older model to 1.7.0 updates");
+            }
+            new MigrateTo1_7_0().migrate(session);
+        }
 
         model.setStoredVersion(MigrationModel.LATEST_VERSION);
     }
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
new file mode 100644
index 0000000..e4ead4d
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java
@@ -0,0 +1,23 @@
+package org.keycloak.migration.migrators;
+
+import java.util.List;
+
+import org.keycloak.migration.ModelVersion;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class MigrateTo1_7_0 {
+
+    public static final ModelVersion VERSION = new ModelVersion("1.7.0");
+
+    public void migrate(KeycloakSession session) {
+        List<RealmModel> realms = session.realms().getRealms();
+        for (RealmModel realm : realms) {
+            realm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT);
+        }
+    }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 051493e..492c2e1 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -111,12 +111,18 @@ public interface ClientModel extends RoleContainerModel {
     boolean isPublicClient();
     void setPublicClient(boolean flag);
 
-    boolean isDirectGrantsOnly();
-    void setDirectGrantsOnly(boolean flag);
-
     boolean isConsentRequired();
     void setConsentRequired(boolean consentRequired);
 
+    boolean isStandardFlowEnabled();
+    void setStandardFlowEnabled(boolean standardFlowEnabled);
+
+    boolean isImplicitFlowEnabled();
+    void setImplicitFlowEnabled(boolean implicitFlowEnabled);
+
+    boolean isDirectAccessGrantsEnabled();
+    void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled);
+
     boolean isServiceAccountsEnabled();
     void setServiceAccountsEnabled(boolean serviceAccountsEnabled);
 
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 3ecc51c..c50e4cd 100755
--- a/model/api/src/main/java/org/keycloak/models/Constants.java
+++ b/model/api/src/main/java/org/keycloak/models/Constants.java
@@ -20,6 +20,8 @@ public interface Constants {
     String[] BROKER_SERVICE_ROLES = {READ_TOKEN_ROLE};
     String OFFLINE_ACCESS_ROLE = OAuth2Constants.OFFLINE_ACCESS;
 
+    // 15 minutes
+    int DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT = 900;
     // 30 days
     int DEFAULT_OFFLINE_SESSION_IDLE_TIMEOUT = 2592000;
 
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 d04699f..b5edbaf 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
@@ -30,6 +30,9 @@ public class ClientEntity extends AbstractIdentifiableEntity {
     private String baseUrl;
     private boolean bearerOnly;
     private boolean consentRequired;
+    private boolean standardFlowEnabled;
+    private boolean implicitFlowEnabled;
+    private boolean directAccessGrantsEnabled;
     private boolean serviceAccountsEnabled;
     private boolean directGrantsOnly;
     private int nodeReRegistrationTimeout;
@@ -243,6 +246,30 @@ public class ClientEntity extends AbstractIdentifiableEntity {
         this.consentRequired = consentRequired;
     }
 
+    public boolean isStandardFlowEnabled() {
+        return standardFlowEnabled;
+    }
+
+    public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+        this.standardFlowEnabled = standardFlowEnabled;
+    }
+
+    public boolean isImplicitFlowEnabled() {
+        return implicitFlowEnabled;
+    }
+
+    public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+        this.implicitFlowEnabled = implicitFlowEnabled;
+    }
+
+    public boolean isDirectAccessGrantsEnabled() {
+        return directAccessGrantsEnabled;
+    }
+
+    public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+        this.directAccessGrantsEnabled = directAccessGrantsEnabled;
+    }
+
     public boolean isServiceAccountsEnabled() {
         return serviceAccountsEnabled;
     }
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
index 8f5c844..7a08bca 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
@@ -44,6 +44,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
     private int ssoSessionMaxLifespan;
     private int offlineSessionIdleTimeout;
     private int accessTokenLifespan;
+    private int accessTokenLifespanForImplicitFlow;
     private int accessCodeLifespan;
     private int accessCodeLifespanUserAction;
     private int accessCodeLifespanLogin;
@@ -272,6 +273,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
         this.accessTokenLifespan = accessTokenLifespan;
     }
 
+    public int getAccessTokenLifespanForImplicitFlow() {
+        return accessTokenLifespanForImplicitFlow;
+    }
+
+    public void setAccessTokenLifespanForImplicitFlow(int accessTokenLifespanForImplicitFlow) {
+        this.accessTokenLifespanForImplicitFlow = accessTokenLifespanForImplicitFlow;
+    }
+
     public int getAccessCodeLifespan() {
         return accessCodeLifespan;
     }
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 62f9162..6c2c260 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -107,6 +107,9 @@ public interface RealmModel extends RoleContainerModel {
 
     void setAccessTokenLifespan(int seconds);
 
+    int getAccessTokenLifespanForImplicitFlow();
+    void setAccessTokenLifespanForImplicitFlow(int seconds);
+
     int getAccessCodeLifespan();
 
     void setAccessCodeLifespan(int seconds);
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 723617b..e60d915 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -205,6 +205,7 @@ public class ModelToRepresentation {
         rep.setEditUsernameAllowed(realm.isEditUsernameAllowed());
         rep.setRevokeRefreshToken(realm.isRevokeRefreshToken());
         rep.setAccessTokenLifespan(realm.getAccessTokenLifespan());
+        rep.setAccessTokenLifespanForImplicitFlow(realm.getAccessTokenLifespanForImplicitFlow());
         rep.setSsoSessionIdleTimeout(realm.getSsoSessionIdleTimeout());
         rep.setSsoSessionMaxLifespan(realm.getSsoSessionMaxLifespan());
         rep.setOfflineSessionIdleTimeout(realm.getOfflineSessionIdleTimeout());
@@ -418,8 +419,10 @@ public class ModelToRepresentation {
         rep.setFullScopeAllowed(clientModel.isFullScopeAllowed());
         rep.setBearerOnly(clientModel.isBearerOnly());
         rep.setConsentRequired(clientModel.isConsentRequired());
+        rep.setStandardFlowEnabled(clientModel.isStandardFlowEnabled());
+        rep.setImplicitFlowEnabled(clientModel.isImplicitFlowEnabled());
+        rep.setDirectAccessGrantsEnabled(clientModel.isDirectAccessGrantsEnabled());
         rep.setServiceAccountsEnabled(clientModel.isServiceAccountsEnabled());
-        rep.setDirectGrantsOnly(clientModel.isDirectGrantsOnly());
         rep.setSurrogateAuthRequired(clientModel.isSurrogateAuthRequired());
         rep.setRootUrl(clientModel.getRootUrl());
         rep.setBaseUrl(clientModel.getBaseUrl());
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 dd82098..8360e48 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
@@ -105,6 +105,9 @@ public class RepresentationToModel {
         if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
         else newRealm.setAccessTokenLifespan(300);
 
+        if (rep.getAccessTokenLifespanForImplicitFlow() != null) newRealm.setAccessTokenLifespanForImplicitFlow(rep.getAccessTokenLifespanForImplicitFlow());
+        else newRealm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT);
+
         if (rep.getSsoSessionIdleTimeout() != null) newRealm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
         else newRealm.setSsoSessionIdleTimeout(1800);
         if (rep.getSsoSessionMaxLifespan() != null) newRealm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
@@ -603,6 +606,7 @@ public class RepresentationToModel {
         if (rep.getNotBefore() != null) realm.setNotBefore(rep.getNotBefore());
         if (rep.getRevokeRefreshToken() != null) realm.setRevokeRefreshToken(rep.getRevokeRefreshToken());
         if (rep.getAccessTokenLifespan() != null) realm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
+        if (rep.getAccessTokenLifespanForImplicitFlow() != null) realm.setAccessTokenLifespanForImplicitFlow(rep.getAccessTokenLifespanForImplicitFlow());
         if (rep.getSsoSessionIdleTimeout() != null) realm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
         if (rep.getSsoSessionMaxLifespan() != null) realm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
         if (rep.getOfflineSessionIdleTimeout() != null) realm.setOfflineSessionIdleTimeout(rep.getOfflineSessionIdleTimeout());
@@ -772,8 +776,17 @@ 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());
-        if (resourceRep.isDirectGrantsOnly() != null) client.setDirectGrantsOnly(resourceRep.isDirectGrantsOnly());
+
+        // 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());
+        }
+
         if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
         if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
         if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
@@ -869,8 +882,10 @@ public class RepresentationToModel {
         if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
         if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
         if (rep.isConsentRequired() != null) resource.setConsentRequired(rep.isConsentRequired());
+        if (rep.isStandardFlowEnabled() != null) resource.setStandardFlowEnabled(rep.isStandardFlowEnabled());
+        if (rep.isImplicitFlowEnabled() != null) resource.setImplicitFlowEnabled(rep.isImplicitFlowEnabled());
+        if (rep.isDirectAccessGrantsEnabled() != null) resource.setDirectAccessGrantsEnabled(rep.isDirectAccessGrantsEnabled());
         if (rep.isServiceAccountsEnabled() != null) resource.setServiceAccountsEnabled(rep.isServiceAccountsEnabled());
-        if (rep.isDirectGrantsOnly() != null) resource.setDirectGrantsOnly(rep.isDirectGrantsOnly());
         if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient());
         if (rep.isFullScopeAllowed() != null) resource.setFullScopeAllowed(rep.isFullScopeAllowed());
         if (rep.isFrontchannelLogout() != null) resource.setFrontchannelLogout(rep.isFrontchannelLogout());
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
index e03452a..20c8725 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
@@ -163,16 +163,6 @@ public class ClientAdapter implements ClientModel {
 
     }
 
-    public boolean isDirectGrantsOnly() {
-        if (updated != null) return updated.isDirectGrantsOnly();
-        return cached.isDirectGrantsOnly();
-    }
-
-    public void setDirectGrantsOnly(boolean flag) {
-        getDelegateForUpdate();
-        updated.setDirectGrantsOnly(flag);
-    }
-
     public Set<RoleModel> getScopeMappings() {
         if (updated != null) return updated.getScopeMappings();
         Set<RoleModel> roles = new HashSet<RoleModel>();
@@ -452,6 +442,42 @@ public class ClientAdapter implements ClientModel {
     }
 
     @Override
+    public boolean isStandardFlowEnabled() {
+        if (updated != null) return updated.isStandardFlowEnabled();
+        return cached.isStandardFlowEnabled();
+    }
+
+    @Override
+    public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+        getDelegateForUpdate();
+        updated.setStandardFlowEnabled(standardFlowEnabled);
+    }
+
+    @Override
+    public boolean isImplicitFlowEnabled() {
+        if (updated != null) return updated.isImplicitFlowEnabled();
+        return cached.isImplicitFlowEnabled();
+    }
+
+    @Override
+    public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+        getDelegateForUpdate();
+        updated.setImplicitFlowEnabled(implicitFlowEnabled);
+    }
+
+    @Override
+    public boolean isDirectAccessGrantsEnabled() {
+        if (updated != null) return updated.isDirectAccessGrantsEnabled();
+        return cached.isDirectAccessGrantsEnabled();
+    }
+
+    @Override
+    public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+        getDelegateForUpdate();
+        updated.setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
+    }
+
+    @Override
     public boolean isServiceAccountsEnabled() {
         if (updated != null) return updated.isServiceAccountsEnabled();
         return cached.isServiceAccountsEnabled();
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
index 02abe5e..c24f151 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
@@ -301,6 +301,18 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public int getAccessTokenLifespanForImplicitFlow() {
+        if (updated != null) return updated.getAccessTokenLifespanForImplicitFlow();
+        return cached.getAccessTokenLifespanForImplicitFlow();
+    }
+
+    @Override
+    public void setAccessTokenLifespanForImplicitFlow(int seconds) {
+        getDelegateForUpdate();
+        updated.setAccessTokenLifespanForImplicitFlow(seconds);
+    }
+
+    @Override
     public int getAccessCodeLifespan() {
         if (updated != null) return updated.getAccessCodeLifespan();
         return cached.getAccessCodeLifespan();
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index 7c7b97d..a683956 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -36,7 +36,6 @@ public class CachedClient implements Serializable {
     private Map<String, String> attributes = new HashMap<String, String>();
     private boolean publicClient;
     private boolean fullScopeAllowed;
-    private boolean directGrantsOnly;
     private boolean frontchannelLogout;
     private int notBefore;
     private Set<String> scope = new HashSet<String>();
@@ -49,6 +48,9 @@ public class CachedClient implements Serializable {
     private List<String> defaultRoles = new LinkedList<String>();
     private boolean bearerOnly;
     private boolean consentRequired;
+    private boolean standardFlowEnabled;
+    private boolean implicitFlowEnabled;
+    private boolean directAccessGrantsEnabled;
     private boolean serviceAccountsEnabled;
     private Map<String, String> roles = new HashMap<String, String>();
     private int nodeReRegistrationTimeout;
@@ -67,7 +69,6 @@ public class CachedClient implements Serializable {
         protocol = model.getProtocol();
         attributes.putAll(model.getAttributes());
         notBefore = model.getNotBefore();
-        directGrantsOnly = model.isDirectGrantsOnly();
         frontchannelLogout = model.isFrontchannelLogout();
         publicClient = model.isPublicClient();
         fullScopeAllowed = model.isFullScopeAllowed();
@@ -86,6 +87,9 @@ public class CachedClient implements Serializable {
         defaultRoles.addAll(model.getDefaultRoles());
         bearerOnly = model.isBearerOnly();
         consentRequired = model.isConsentRequired();
+        standardFlowEnabled = model.isStandardFlowEnabled();
+        implicitFlowEnabled = model.isImplicitFlowEnabled();
+        directAccessGrantsEnabled = model.isDirectAccessGrantsEnabled();
         serviceAccountsEnabled = model.isServiceAccountsEnabled();
         for (RoleModel role : model.getRoles()) {
             roles.put(role.getName(), role.getId());
@@ -139,10 +143,6 @@ public class CachedClient implements Serializable {
         return publicClient;
     }
 
-    public boolean isDirectGrantsOnly() {
-        return directGrantsOnly;
-    }
-
     public int getNotBefore() {
         return notBefore;
     }
@@ -203,6 +203,18 @@ public class CachedClient implements Serializable {
         return consentRequired;
     }
 
+    public boolean isStandardFlowEnabled() {
+        return standardFlowEnabled;
+    }
+
+    public boolean isImplicitFlowEnabled() {
+        return implicitFlowEnabled;
+    }
+
+    public boolean isDirectAccessGrantsEnabled() {
+        return directAccessGrantsEnabled;
+    }
+
     public boolean isServiceAccountsEnabled() {
         return serviceAccountsEnabled;
     }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index 4ae07fd..e423562 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -61,6 +61,7 @@ public class CachedRealm implements Serializable {
     private int ssoSessionMaxLifespan;
     private int offlineSessionIdleTimeout;
     private int accessTokenLifespan;
+    private int accessTokenLifespanForImplicitFlow;
     private int accessCodeLifespan;
     private int accessCodeLifespanUserAction;
     private int accessCodeLifespanLogin;
@@ -146,6 +147,7 @@ public class CachedRealm implements Serializable {
         ssoSessionMaxLifespan = model.getSsoSessionMaxLifespan();
         offlineSessionIdleTimeout = model.getOfflineSessionIdleTimeout();
         accessTokenLifespan = model.getAccessTokenLifespan();
+        accessTokenLifespanForImplicitFlow = model.getAccessTokenLifespanForImplicitFlow();
         accessCodeLifespan = model.getAccessCodeLifespan();
         accessCodeLifespanUserAction = model.getAccessCodeLifespanUserAction();
         accessCodeLifespanLogin = model.getAccessCodeLifespanLogin();
@@ -347,6 +349,10 @@ public class CachedRealm implements Serializable {
         return accessTokenLifespan;
     }
 
+    public int getAccessTokenLifespanForImplicitFlow() {
+        return accessTokenLifespanForImplicitFlow;
+    }
+
     public int getAccessCodeLifespan() {
         return accessCodeLifespan;
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 6cb24f8..f677859 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -499,23 +499,43 @@ public class ClientAdapter implements ClientModel {
     }
 
     @Override
-    public boolean isServiceAccountsEnabled() {
-        return entity.isServiceAccountsEnabled();
+    public boolean isStandardFlowEnabled() {
+        return entity.isStandardFlowEnabled();
     }
 
     @Override
-    public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
-        entity.setServiceAccountsEnabled(serviceAccountsEnabled);
+    public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+        entity.setStandardFlowEnabled(standardFlowEnabled);
+    }
+
+    @Override
+    public boolean isImplicitFlowEnabled() {
+        return entity.isImplicitFlowEnabled();
+    }
+
+    @Override
+    public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+        entity.setImplicitFlowEnabled(implicitFlowEnabled);
     }
 
     @Override
-    public boolean isDirectGrantsOnly() {
-        return entity.isDirectGrantsOnly();
+    public boolean isDirectAccessGrantsEnabled() {
+        return entity.isDirectAccessGrantsEnabled();
     }
 
     @Override
-    public void setDirectGrantsOnly(boolean flag) {
-        entity.setDirectGrantsOnly(flag);
+    public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+        entity.setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
+    }
+
+    @Override
+    public boolean isServiceAccountsEnabled() {
+        return entity.isServiceAccountsEnabled();
+    }
+
+    @Override
+    public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+        entity.setServiceAccountsEnabled(serviceAccountsEnabled);
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index 6218e26..1569875 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -95,15 +95,21 @@ public class ClientEntity {
     @Column(name="MANAGEMENT_URL")
     private String managementUrl;
 
-    @Column(name="DIRECT_GRANTS_ONLY")
-    protected boolean directGrantsOnly;
-
     @Column(name="BEARER_ONLY")
     private boolean bearerOnly;
 
     @Column(name="CONSENT_REQUIRED")
     private boolean consentRequired;
 
+    @Column(name="STANDARD_FLOW_ENABLED")
+    private boolean standardFlowEnabled;
+
+    @Column(name="IMPLICIT_FLOW_ENABLED")
+    private boolean implicitFlowEnabled;
+
+    @Column(name="DIRECT_ACCESS_GRANTS_ENABLED")
+    private boolean directAccessGrantsEnabled;
+
     @Column(name="SERVICE_ACCOUNTS_ENABLED")
     private boolean serviceAccountsEnabled;
 
@@ -339,20 +345,36 @@ public class ClientEntity {
         this.consentRequired = consentRequired;
     }
 
-    public boolean isServiceAccountsEnabled() {
-        return serviceAccountsEnabled;
+    public boolean isStandardFlowEnabled() {
+        return standardFlowEnabled;
     }
 
-    public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
-        this.serviceAccountsEnabled = serviceAccountsEnabled;
+    public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+        this.standardFlowEnabled = standardFlowEnabled;
+    }
+
+    public boolean isImplicitFlowEnabled() {
+        return implicitFlowEnabled;
     }
 
-    public boolean isDirectGrantsOnly() {
-        return directGrantsOnly;
+    public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+        this.implicitFlowEnabled = implicitFlowEnabled;
     }
 
-    public void setDirectGrantsOnly(boolean directGrantsOnly) {
-        this.directGrantsOnly = directGrantsOnly;
+    public boolean isDirectAccessGrantsEnabled() {
+        return directAccessGrantsEnabled;
+    }
+
+    public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+        this.directAccessGrantsEnabled = directAccessGrantsEnabled;
+    }
+
+    public boolean isServiceAccountsEnabled() {
+        return serviceAccountsEnabled;
+    }
+
+    public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+        this.serviceAccountsEnabled = serviceAccountsEnabled;
     }
 
     public int getNodeReRegistrationTimeout() {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index 6492b81..05af313 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -86,6 +86,8 @@ public class RealmEntity {
     private int offlineSessionIdleTimeout;
     @Column(name="ACCESS_TOKEN_LIFESPAN")
     protected int accessTokenLifespan;
+    @Column(name="ACCESS_TOKEN_LIFE_IMPLICIT")
+    protected int accessTokenLifespanForImplicitFlow;
     @Column(name="ACCESS_CODE_LIFESPAN")
     protected int accessCodeLifespan;
     @Column(name="USER_ACTION_LIFESPAN")
@@ -336,6 +338,14 @@ public class RealmEntity {
         this.accessTokenLifespan = accessTokenLifespan;
     }
 
+    public int getAccessTokenLifespanForImplicitFlow() {
+        return accessTokenLifespanForImplicitFlow;
+    }
+
+    public void setAccessTokenLifespanForImplicitFlow(int accessTokenLifespanForImplicitFlow) {
+        this.accessTokenLifespanForImplicitFlow = accessTokenLifespanForImplicitFlow;
+    }
+
     public int getAccessCodeLifespan() {
         return accessCodeLifespan;
     }
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 acc5182..cb69f14 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
@@ -361,6 +361,16 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public int getAccessTokenLifespanForImplicitFlow() {
+        return realm.getAccessTokenLifespanForImplicitFlow();
+    }
+
+    @Override
+    public void setAccessTokenLifespanForImplicitFlow(int seconds) {
+        realm.setAccessTokenLifespanForImplicitFlow(seconds);
+    }
+
+    @Override
     public int getSsoSessionIdleTimeout() {
         return realm.getSsoSessionIdleTimeout();
     }
@@ -715,6 +725,8 @@ public class RealmAdapter implements RealmModel {
         entity.setId(id);
         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/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index fc1f13d..eb6bcd9 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -505,24 +505,46 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
     }
 
     @Override
-    public boolean isServiceAccountsEnabled() {
-        return getMongoEntity().isServiceAccountsEnabled();
+    public boolean isStandardFlowEnabled() {
+        return getMongoEntity().isStandardFlowEnabled();
     }
 
     @Override
-    public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
-        getMongoEntity().setServiceAccountsEnabled(serviceAccountsEnabled);
+    public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+        getMongoEntity().setStandardFlowEnabled(standardFlowEnabled);
+        updateMongoEntity();
+    }
+
+    @Override
+    public boolean isImplicitFlowEnabled() {
+        return getMongoEntity().isImplicitFlowEnabled();
+    }
+
+    @Override
+    public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+        getMongoEntity().setImplicitFlowEnabled(implicitFlowEnabled);
         updateMongoEntity();
     }
 
     @Override
-    public boolean isDirectGrantsOnly() {
-        return getMongoEntity().isDirectGrantsOnly();
+    public boolean isDirectAccessGrantsEnabled() {
+        return getMongoEntity().isDirectAccessGrantsEnabled();
     }
 
     @Override
-    public void setDirectGrantsOnly(boolean flag) {
-        getMongoEntity().setDirectGrantsOnly(flag);
+    public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+        getMongoEntity().setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
+        updateMongoEntity();
+    }
+
+    @Override
+    public boolean isServiceAccountsEnabled() {
+        return getMongoEntity().isServiceAccountsEnabled();
+    }
+
+    @Override
+    public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+        getMongoEntity().setServiceAccountsEnabled(serviceAccountsEnabled);
         updateMongoEntity();
     }
 
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 d31503c..c8fc1f0 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
@@ -369,6 +369,17 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
+    public int getAccessTokenLifespanForImplicitFlow() {
+        return realm.getAccessTokenLifespanForImplicitFlow();
+    }
+
+    @Override
+    public void setAccessTokenLifespanForImplicitFlow(int seconds) {
+        realm.setAccessTokenLifespanForImplicitFlow(seconds);
+        updateRealm();
+    }
+
+    @Override
     public int getAccessCodeLifespan() {
         return realm.getAccessCodeLifespan();
     }
@@ -799,6 +810,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         clientEntity.setClientId(clientId);
         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/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index ff1275a..3402593 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -142,15 +142,15 @@ public class SamlService extends AuthorizationEndpointBase {
                 event.error(Errors.CLIENT_DISABLED);
                 return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
             }
-            if ((client instanceof ClientModel) && ((ClientModel) client).isBearerOnly()) {
+            if (client.isBearerOnly()) {
                 event.event(EventType.LOGIN);
                 event.error(Errors.NOT_ALLOWED);
                 return ErrorPage.error(session, Messages.BEARER_ONLY);
             }
-            if (client.isDirectGrantsOnly()) {
+            if (!client.isStandardFlowEnabled()) {
                 event.event(EventType.LOGIN);
                 event.error(Errors.NOT_ALLOWED);
-                return ErrorPage.error(session, Messages.DIRECT_GRANTS_ONLY);
+                return ErrorPage.error(session, Messages.STANDARD_FLOW_DISABLED);
             }
 
             session.getContext().setClient(client);
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index b1d4162..710c77d 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -470,7 +470,8 @@ public class AuthenticationProcessor {
             LoginProtocol protocol = getSession().getProvider(LoginProtocol.class, getClientSession().getAuthMethod());
             protocol.setRealm(getRealm())
                     .setHttpHeaders(getHttpRequest().getHttpHeaders())
-                    .setUriInfo(getUriInfo());
+                    .setUriInfo(getUriInfo())
+                    .setEventBuilder(event);
             Response response = protocol.sendError(getClientSession(), Error.CANCELLED_BY_USER);
             forceChallenge(response);
         }
@@ -808,7 +809,7 @@ public class AuthenticationProcessor {
     public Response finishAuthentication() {
         event.success();
         RealmModel realm = clientSession.getRealm();
-        return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, connection);
+        return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, connection, event);
 
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index c8d5656..9ed45de 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -1,19 +1,11 @@
 package org.keycloak.protocol.oidc.endpoints;
 
-import java.util.List;
-
 import javax.ws.rs.GET;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
 
 import org.jboss.logging.Logger;
-import org.jboss.resteasy.spi.HttpRequest;
-import org.keycloak.OAuth2Constants;
 import org.keycloak.authentication.AuthenticationProcessor;
-import org.keycloak.common.ClientConnection;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
@@ -24,12 +16,12 @@ import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.IdentityProviderModel;
-import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.AuthorizationEndpointBase;
-import org.keycloak.protocol.RestartLoginCookie;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.services.ErrorPageException;
 import org.keycloak.services.Urls;
@@ -55,11 +47,13 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
     private ClientSessionModel clientSession;
 
     private Action action;
+    private OIDCResponseType parsedResponseType;
 
     private String clientId;
     private String redirectUri;
     private String redirectUriParam;
     private String responseType;
+    private String responseMode;
     private String state;
     private String scope;
     private String loginHint;
@@ -80,6 +74,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
 
         clientId = params.getFirst(OIDCLoginProtocol.CLIENT_ID_PARAM);
         responseType = params.getFirst(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+        responseMode = params.getFirst(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
         redirectUriParam = params.getFirst(OIDCLoginProtocol.REDIRECT_URI_PARAM);
         state = params.getFirst(OIDCLoginProtocol.STATE_PARAM);
         scope = params.getFirst(OIDCLoginProtocol.SCOPE_PARAM);
@@ -90,8 +85,8 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
 
         checkSsl();
         checkRealm();
-        checkClient();
         checkResponseType();
+        checkClient();
         checkRedirectUri();
 
         createClientSession();
@@ -172,9 +167,14 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
             throw new ErrorPageException(session, Messages.BEARER_ONLY);
         }
 
-        if (client.isDirectGrantsOnly()) {
+        if ((parsedResponseType.hasResponseType(OIDCResponseType.CODE) || parsedResponseType.hasResponseType(OIDCResponseType.NONE)) && !client.isStandardFlowEnabled()) {
             event.error(Errors.NOT_ALLOWED);
-            throw new ErrorPageException(session, Messages.DIRECT_GRANTS_ONLY);
+            throw new ErrorPageException(session, Messages.STANDARD_FLOW_DISABLED);
+        }
+
+        if (parsedResponseType.isImplicitOrHybridFlow() && !client.isImplicitFlowEnabled()) {
+            event.error(Errors.NOT_ALLOWED);
+            throw new ErrorPageException(session, Messages.IMPLICIT_FLOW_DISABLED);
         }
 
         session.getContext().setClient(client);
@@ -192,14 +192,32 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
 
         event.detail(Details.RESPONSE_TYPE, responseType);
 
-        if (responseType.equals(OAuth2Constants.CODE)) {
+        try {
+            parsedResponseType = OIDCResponseType.parse(responseType);
             if (action == null) {
                 action = Action.CODE;
             }
-        } else {
+        } catch (IllegalArgumentException iae) {
+            logger.error(iae.getMessage());
             event.error(Errors.INVALID_REQUEST);
             throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
         }
+
+        try {
+            OIDCResponseMode parsedResponseMode = OIDCResponseMode.parse(responseMode, parsedResponseType);
+            event.detail(Details.RESPONSE_MODE, parsedResponseMode.toString().toLowerCase());
+
+            // Disallowed by OIDC specs
+            if (parsedResponseType.isImplicitOrHybridFlow() && parsedResponseMode == OIDCResponseMode.QUERY) {
+                logger.error("Response_mode 'query' not allowed for implicit or hybrid flow");
+                event.error(Errors.INVALID_REQUEST);
+                throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+            }
+
+        } catch (IllegalArgumentException iae) {
+            event.error(Errors.INVALID_REQUEST);
+            throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+        }
     }
 
     private void checkRedirectUri() {
@@ -228,6 +246,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
         if (loginHint != null) clientSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint);
         if (prompt != null) clientSession.setNote(OIDCLoginProtocol.PROMPT_PARAM, prompt);
         if (idpHint != null) clientSession.setNote(AdapterConstants.KC_IDP_HINT, idpHint);
+        if (responseMode != null) clientSession.setNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM, responseMode);
     }
 
     private Response buildAuthorizationCodeAuthorizationResponse() {
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 c790661..fe358e0 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
@@ -327,7 +327,7 @@ public class TokenEndpoint {
     }
 
     public Response buildResourceOwnerPasswordCredentialsGrant() {
-        event.detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, "token");
+        event.detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD);
 
         if (client.isConsentRequired()) {
             event.error(Errors.CONSENT_DENIED);
@@ -393,7 +393,7 @@ public class TokenEndpoint {
             throw new ErrorResponseException("unauthorized_client", "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
         }
 
-        event.detail(Details.RESPONSE_TYPE, ServiceAccountConstants.CLIENT_AUTH);
+        event.detail(Details.RESPONSE_TYPE, OAuth2Constants.CLIENT_CREDENTIALS);
 
         UserModel clientUser = session.users().getUserByServiceAccountClient(client);
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index b9d55db..40bcc67 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -33,6 +33,10 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.RestartLoginCookie;
+import org.keycloak.protocol.oidc.utils.OIDCRedirectUriBuilder;
+import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.managers.ResourceAdminManager;
 
@@ -62,6 +66,8 @@ public class OIDCLoginProtocol implements LoginProtocol {
     public static final String LOGOUT_REDIRECT_URI = "OIDC_LOGOUT_REDIRECT_URI";
     public static final String ISSUER = "iss";
 
+    public static final String RESPONSE_MODE_PARAM = "response_mode";
+
     private static final Logger log = Logger.getLogger(OIDCLoginProtocol.class);
 
     protected KeycloakSession session;
@@ -74,6 +80,9 @@ public class OIDCLoginProtocol implements LoginProtocol {
 
     protected EventBuilder event;
 
+    protected OIDCResponseType responseType;
+    protected OIDCResponseMode responseMode;
+
     public OIDCLoginProtocol(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, EventBuilder event) {
         this.session = session;
         this.realm = realm;
@@ -86,6 +95,15 @@ public class OIDCLoginProtocol implements LoginProtocol {
 
     }
 
+    private void setupResponseTypeAndMode(ClientSessionModel clientSession) {
+        String responseType = clientSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+        String responseMode = clientSession.getNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+        this.responseType = OIDCResponseType.parse(responseType);
+        this.responseMode = OIDCResponseMode.parse(responseMode, this.responseType);
+        this.event.detail(Details.RESPONSE_TYPE, responseType);
+        this.event.detail(Details.RESPONSE_MODE, this.responseMode.toString().toLowerCase());
+    }
+
     @Override
     public OIDCLoginProtocol setSession(KeycloakSession session) {
         this.session = session;
@@ -116,32 +134,63 @@ public class OIDCLoginProtocol implements LoginProtocol {
         return this;
     }
 
+
     @Override
     public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) {
         ClientSessionModel clientSession = accessCode.getClientSession();
+        setupResponseTypeAndMode(clientSession);
+
         String redirect = clientSession.getRedirectUri();
+        OIDCRedirectUriBuilder redirectUri = OIDCRedirectUriBuilder.fromUri(redirect, responseMode);
         String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM);
-        accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
-        UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.CODE, accessCode.getCode());
         log.debugv("redirectAccessCode: state: {0}", state);
         if (state != null)
-            redirectUri.queryParam(OAuth2Constants.STATE, state);
-        Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
+            redirectUri.addParam(OAuth2Constants.STATE, state);
 
-        return location.build();
+        // Standard or hybrid flow
+        if (responseType.hasResponseType(OIDCResponseType.CODE)) {
+            accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
+            redirectUri.addParam(OAuth2Constants.CODE, accessCode.getCode());
+        }
+
+        // Implicit or hybrid flow
+        if (responseType.isImplicitOrHybridFlow()) {
+            TokenManager tokenManager = new TokenManager();
+            AccessTokenResponse res = tokenManager.responseBuilder(realm, clientSession.getClient(), event, session, userSession, clientSession)
+                    .generateAccessToken()
+                    .generateIDToken()
+                    .build();
+
+            if (responseType.hasResponseType(OIDCResponseType.ID_TOKEN)) {
+                redirectUri.addParam("id_token", res.getIdToken());
+            }
+
+            if (responseType.hasResponseType(OIDCResponseType.TOKEN)) {
+                redirectUri.addParam("access_token", res.getToken());
+                redirectUri.addParam("token_type", res.getTokenType());
+                redirectUri.addParam("session-state", res.getSessionState());
+                redirectUri.addParam("expires_in", String.valueOf(res.getExpiresIn()));
+            }
+
+            redirectUri.addParam("not-before-policy", String.valueOf(res.getNotBeforePolicy()));
+        }
+
+        return redirectUri.build();
     }
 
+
     @Override
     public Response sendError(ClientSessionModel clientSession, Error error) {
+        setupResponseTypeAndMode(clientSession);
+
         String redirect = clientSession.getRedirectUri();
         String state = clientSession.getNote(OIDCLoginProtocol.STATE_PARAM);
-        UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.ERROR, translateError(error));
+        OIDCRedirectUriBuilder redirectUri = OIDCRedirectUriBuilder.fromUri(redirect, responseMode).addParam(OAuth2Constants.ERROR, translateError(error));
         if (state != null)
-            redirectUri.queryParam(OAuth2Constants.STATE, state);
+            redirectUri.addParam(OAuth2Constants.STATE, state);
         session.sessions().removeClientSession(realm, clientSession);
         RestartLoginCookie.expireRestartCookie(realm, session.getContext().getConnection(), uriInfo);
-        Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
-        return location.build();
+        return redirectUri.build();
     }
 
     private String translateError(Error error) {
@@ -161,10 +210,8 @@ public class OIDCLoginProtocol implements LoginProtocol {
 
     @Override
     public void backchannelLogout(UserSessionModel userSession, ClientSessionModel clientSession) {
-        if (!(clientSession.getClient() instanceof ClientModel))
-            return;
-        ClientModel app = clientSession.getClient();
-        new ResourceAdminManager(session).logoutClientSession(uriInfo.getRequestUri(), realm, app, clientSession);
+        ClientModel client = clientSession.getClient();
+        new ResourceAdminManager(session).logoutClientSession(uriInfo.getRequestUri(), realm, client, clientSession);
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 304e6af..e76734e 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -26,6 +26,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.ProtocolMapper;
 import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
 import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.protocol.oidc.utils.WebOriginsUtils;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AccessTokenResponse;
@@ -52,7 +53,7 @@ import java.util.Map;
 import java.util.Set;
 
 /**
- * Stateful object that creates tokens and manages oauth access codes
+ * Stateless object that creates tokens and manages oauth access codes
  *
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
@@ -455,8 +456,9 @@ public class TokenManager {
         if (session != null) {
             token.setSessionState(session.getId());
         }
-        if (realm.getAccessTokenLifespan() > 0) {
-            token.expiration(Time.currentTime() + realm.getAccessTokenLifespan());
+        int tokenLifespan = getTokenLifespan(realm, clientSession);
+        if (tokenLifespan > 0) {
+            token.expiration(Time.currentTime() + tokenLifespan);
         }
         Set<String> allowedOrigins = client.getWebOrigins();
         if (allowedOrigins != null) {
@@ -465,6 +467,15 @@ public class TokenManager {
         return token;
     }
 
+    private int getTokenLifespan(RealmModel realm, ClientSessionModel clientSession) {
+        boolean implicitFlow = false;
+        String responseType = clientSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+        if (responseType != null) {
+            implicitFlow = OIDCResponseType.parse(responseType).isImplicitFlow();
+        }
+        return implicitFlow ? realm.getAccessTokenLifespanForImplicitFlow() : realm.getAccessTokenLifespan();
+    }
+
     protected void addComposites(AccessToken token, RoleModel role) {
         AccessToken.Access access = null;
         if (role.getContainer() instanceof RealmModel) {
@@ -582,9 +593,7 @@ public class TokenManager {
             idToken.issuer(accessToken.getIssuer());
             idToken.setNonce(accessToken.getNonce());
             idToken.setSessionState(accessToken.getSessionState());
-            if (realm.getAccessTokenLifespan() > 0) {
-                idToken.expiration(Time.currentTime() + realm.getAccessTokenLifespan());
-            }
+            idToken.expiration(accessToken.getExpiration());
             transformIDToken(session, idToken, realm, client, userSession.getUser(), userSession, clientSession);
             return this;
         }
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
new file mode 100644
index 0000000..06cc3cc
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java
@@ -0,0 +1,149 @@
+package org.keycloak.protocol.oidc.utils;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.keycloak.common.util.Encode;
+import org.keycloak.common.util.KeycloakUriBuilder;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class OIDCRedirectUriBuilder {
+
+    protected final KeycloakUriBuilder uriBuilder;
+
+    protected OIDCRedirectUriBuilder(KeycloakUriBuilder uriBuilder) {
+        this.uriBuilder = uriBuilder;
+    }
+
+    public abstract OIDCRedirectUriBuilder addParam(String paramName, String paramValue);
+    public abstract Response build();
+
+
+    public static OIDCRedirectUriBuilder fromUri(String baseUri, OIDCResponseMode responseMode) {
+        KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(baseUri);
+
+        switch (responseMode) {
+            case QUERY: return new QueryRedirectUriBuilder(uriBuilder);
+            case FRAGMENT: return new FragmentRedirectUriBuilder(uriBuilder);
+            case FORM_POST: return new FormPostRedirectUriBuilder(uriBuilder);
+        }
+
+        throw new IllegalStateException("Not possible to end here");
+    }
+
+
+    // Impl subclasses
+
+
+    // http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
+    public static class QueryRedirectUriBuilder extends OIDCRedirectUriBuilder {
+
+        protected QueryRedirectUriBuilder(KeycloakUriBuilder uriBuilder) {
+            super(uriBuilder);
+        }
+
+        @Override
+        public OIDCRedirectUriBuilder addParam(String paramName, String paramValue) {
+            uriBuilder.queryParam(paramName, paramValue);
+            return this;
+        }
+
+        @Override
+        public Response build() {
+            URI redirectUri = uriBuilder.build();
+            Response.ResponseBuilder location = Response.status(302).location(redirectUri);
+            return location.build();
+        }
+    }
+
+
+    // http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
+    public static class FragmentRedirectUriBuilder extends OIDCRedirectUriBuilder {
+
+        private StringBuilder fragment;
+
+        protected FragmentRedirectUriBuilder(KeycloakUriBuilder uriBuilder) {
+            super(uriBuilder);
+        }
+
+        @Override
+        public OIDCRedirectUriBuilder addParam(String paramName, String paramValue) {
+            String param = paramName + "=" + Encode.encodeQueryParam(paramValue);
+            if (fragment == null) {
+                fragment = new StringBuilder(param);
+            } else {
+                fragment.append("&").append(param);
+            }
+            return this;
+        }
+
+        @Override
+        public Response build() {
+            if (fragment != null) {
+                uriBuilder.encodedFragment(fragment.toString());
+            }
+            URI redirectUri = uriBuilder.build();
+
+            Response.ResponseBuilder location = Response.status(302).location(redirectUri);
+            return location.build();
+        }
+
+    }
+
+
+    // http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
+    public static class FormPostRedirectUriBuilder extends OIDCRedirectUriBuilder {
+
+        private Map<String, String> params = new HashMap<>();
+
+        protected FormPostRedirectUriBuilder(KeycloakUriBuilder uriBuilder) {
+            super(uriBuilder);
+        }
+
+        @Override
+        public OIDCRedirectUriBuilder addParam(String paramName, String paramValue) {
+            params.put(paramName, Encode.encodeQueryParam(paramValue));
+            return this;
+        }
+
+        @Override
+        public Response build() {
+            StringBuilder builder = new StringBuilder();
+            URI redirectUri = uriBuilder.build();
+
+            builder.append("<HTML>");
+            builder.append("  <HEAD>");
+            builder.append("    <TITLE>OIDC Form_Post Response</TITLE>");
+            builder.append("  </HEAD>");
+            builder.append("  <BODY Onload=\"document.forms[0].submit()\">");
+
+            builder.append("    <FORM METHOD=\"POST\" ACTION=\"" + redirectUri.toString() + "\">");
+
+            for (Map.Entry<String, String> param : params.entrySet()) {
+                builder.append("  <INPUT TYPE=\"HIDDEN\" NAME=\"").append(param.getKey())
+                        .append("\" VALUE=\"").append(param.getValue()).append("\" />");
+            }
+
+            builder.append("      <NOSCRIPT>");
+            builder.append("        <P>JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue .</P>");
+            builder.append("        <INPUT name=\"continue\" TYPE=\"SUBMIT\" VALUE=\"CONTINUE\" />");
+            builder.append("      </NOSCRIPT>");
+            builder.append("    </FORM>");
+            builder.append("  </BODY>");
+            builder.append("</HTML>");
+
+            return Response.status(Response.Status.OK)
+                    .type(MediaType.TEXT_HTML_TYPE)
+                    .entity(builder.toString()).build();
+        }
+
+    }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseMode.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseMode.java
new file mode 100644
index 0000000..c255ccc
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseMode.java
@@ -0,0 +1,25 @@
+package org.keycloak.protocol.oidc.utils;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public enum OIDCResponseMode {
+
+    QUERY, FRAGMENT, FORM_POST;
+
+    public static OIDCResponseMode parse(String responseMode, OIDCResponseType responseType) {
+        if (responseMode == null) {
+            return getDefaultResponseMode(responseType);
+        } else {
+            return Enum.valueOf(OIDCResponseMode.class, responseMode.toUpperCase());
+        }
+    }
+
+    private static OIDCResponseMode getDefaultResponseMode(OIDCResponseType responseType) {
+        if (responseType.isImplicitOrHybridFlow()) {
+            return OIDCResponseMode.FRAGMENT;
+        } else {
+            return OIDCResponseMode.QUERY;
+        }
+    }
+}
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
new file mode 100644
index 0000000..6377b22
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java
@@ -0,0 +1,93 @@
+package org.keycloak.protocol.oidc.utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCResponseType {
+
+    public static final String CODE = OIDCLoginProtocol.CODE_PARAM;
+    public static final String TOKEN = "token";
+    public static final String ID_TOKEN = "id_token";
+    public static final String NONE = "none";
+
+    private static final List<String> ALLOWED_RESPONSE_TYPES = Arrays.asList(CODE, TOKEN, ID_TOKEN, NONE);
+
+    private final List<String> responseTypes;
+
+
+    private OIDCResponseType(List<String> responseTypes) {
+        this.responseTypes = responseTypes;
+    }
+
+
+    public static OIDCResponseType parse(String responseTypeParam) {
+        if (responseTypeParam == null) {
+            throw new IllegalArgumentException("response_type is null");
+        }
+
+        String[] responseTypes = responseTypeParam.trim().split(" ");
+        List<String> allowedTypes = new ArrayList<>();
+        for (String current : responseTypes) {
+            if (ALLOWED_RESPONSE_TYPES.contains(current)) {
+                allowedTypes.add(current);
+            } else {
+                throw new IllegalArgumentException("Unsupported response_type: " + responseTypeParam);
+            }
+        }
+
+        validateAllowedTypes(allowedTypes);
+
+        return new OIDCResponseType(allowedTypes);
+    }
+
+    private static void validateAllowedTypes(List<String> responseTypes) {
+        if (responseTypes.size() == 0) {
+            throw new IllegalStateException("No responseType provided");
+        }
+        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");
+        }
+    }
+
+
+    public boolean hasResponseType(String responseType) {
+        return responseTypes.contains(responseType);
+    }
+
+
+    public boolean isImplicitOrHybridFlow() {
+        return hasResponseType(TOKEN) || hasResponseType(ID_TOKEN);
+    }
+
+    public boolean isImplicitFlow() {
+        return hasResponseType(TOKEN) && hasResponseType(ID_TOKEN) && !hasResponseType(CODE);
+    }
+
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        boolean first = true;
+        for (String responseType : responseTypes) {
+            if (!first) {
+                builder.append(" ");
+            } else {
+                first = false;
+            }
+            builder.append(responseType);
+        }
+        return builder.toString();
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 0fa1b92..a868aa8 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -43,6 +43,7 @@ public class ApplianceBootstrap {
             realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
             realm.setSsoSessionIdleTimeout(1800);
             realm.setAccessTokenLifespan(60);
+            realm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT);
             realm.setSsoSessionMaxLifespan(36000);
             realm.setOfflineSessionIdleTimeout(Constants.DEFAULT_OFFLINE_SESSION_IDLE_TIMEOUT);
             realm.setAccessCodeLifespan(60);
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index c820e4d..0131b6d 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -380,7 +380,8 @@ public class AuthenticationManager {
 
     public static Response redirectAfterSuccessfulFlow(KeycloakSession session, RealmModel realm, UserSessionModel userSession,
                                                 ClientSessionModel clientSession,
-                                                HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection) {
+                                                HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
+                                                EventBuilder event) {
         Cookie sessionCookie = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_SESSION_COOKIE);
         if (sessionCookie != null) {
 
@@ -407,7 +408,8 @@ public class AuthenticationManager {
         LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
         protocol.setRealm(realm)
                 .setHttpHeaders(request.getHttpHeaders())
-                .setUriInfo(uriInfo);
+                .setUriInfo(uriInfo)
+                .setEventBuilder(event);
         RestartLoginCookie.expireRestartCookie(realm, clientConnection, uriInfo);
         return protocol.authenticated(userSession, new ClientSessionCode(realm, clientSession));
 
@@ -429,7 +431,7 @@ public class AuthenticationManager {
         }
         event.success();
         RealmModel realm = clientSession.getRealm();
-        return redirectAfterSuccessfulFlow(session, realm , userSession, clientSession, request, uriInfo, clientConnection);
+        return redirectAfterSuccessfulFlow(session, realm , userSession, clientSession, request, uriInfo, clientConnection, event);
 
     }
 
@@ -522,9 +524,11 @@ public class AuthenticationManager {
                 LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, context.getClientSession().getAuthMethod());
                 protocol.setRealm(context.getRealm())
                         .setHttpHeaders(context.getHttpRequest().getHttpHeaders())
-                        .setUriInfo(context.getUriInfo());
+                        .setUriInfo(context.getUriInfo())
+                        .setEventBuilder(event);
+                Response response = protocol.sendError(context.getClientSession(), Error.CONSENT_DENIED);
                 event.error(Errors.REJECTED_BY_USER);
-                return protocol.sendError(context.getClientSession(), Error.CONSENT_DENIED);
+                return response;
             }
             else if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) {
                 clientSession.setNote(CURRENT_REQUIRED_ACTION, model.getProviderId());
diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java
index 5f2eeb3..ca1db96 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -110,7 +110,9 @@ public class Messages {
 
     public static final String BEARER_ONLY = "bearerOnlyMessage";
 
-    public static final String DIRECT_GRANTS_ONLY = "directGrantsOnlyMessage";
+    public static final String STANDARD_FLOW_DISABLED = "standardFlowDisabledMessage";
+
+    public static final String IMPLICIT_FLOW_DISABLED = "implicitFlowDisabledMessage";
 
     public static final String INVALID_REDIRECT_URI = "invalidRedirectUriMessage";
 
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index bc83df5..36e4c6c 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -59,6 +59,8 @@ import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.RestartLoginCookie;
 import org.keycloak.protocol.LoginProtocol.Error;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.services.ErrorPage;
 import org.keycloak.services.Urls;
 import org.keycloak.services.managers.AuthenticationManager;
@@ -546,7 +548,7 @@ public class LoginActionsService {
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public Response processConsent(final MultivaluedMap<String, String> formData) {
-        event.event(EventType.LOGIN).detail(Details.RESPONSE_TYPE, "code");
+        event.event(EventType.LOGIN);
 
 
         if (!checkSsl()) {
@@ -561,38 +563,28 @@ public class LoginActionsService {
             return ErrorPage.error(session, Messages.INVALID_ACCESS_CODE);
         }
         ClientSessionModel clientSession = accessCode.getClientSession();
-        event.detail(Details.CODE_ID, clientSession.getId());
 
-        String redirect = clientSession.getRedirectUri();
+        initEvent(clientSession);
+
         UserSessionModel userSession = clientSession.getUserSession();
         UserModel user = userSession.getUser();
         ClientModel client = clientSession.getClient();
 
-        event.client(client)
-                .user(user)
-                .detail(Details.RESPONSE_TYPE, "code")
-                .detail(Details.REDIRECT_URI, redirect);
-
-        event.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
-        event.detail(Details.USERNAME, userSession.getLoginUsername());
-        if (userSession.isRememberMe()) {
-            event.detail(Details.REMEMBER_ME, "true");
-        }
-
         if (!AuthenticationManager.isSessionValid(realm, userSession)) {
             AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers, true);
             event.error(Errors.INVALID_CODE);
             return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE);
         }
-        event.session(userSession);
 
         if (formData.containsKey("cancel")) {
             LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
             protocol.setRealm(realm)
                     .setHttpHeaders(headers)
-                    .setUriInfo(uriInfo);
+                    .setUriInfo(uriInfo)
+                    .setEventBuilder(event);
+            Response response = protocol.sendError(clientSession, Error.CONSENT_DENIED);
             event.error(Errors.REJECTED_BY_USER);
-            return protocol.sendError(clientSession, Error.CONSENT_DENIED);
+            return response;
         }
 
         UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
@@ -613,7 +605,7 @@ public class LoginActionsService {
         event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED);
         event.success();
 
-        return authManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection);
+        return authManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection, event);
     }
 
     @Path("email-verification")
@@ -727,22 +719,27 @@ public class LoginActionsService {
     }
 
     private void initEvent(ClientSessionModel clientSession) {
+        UserSessionModel userSession = clientSession.getUserSession();
+
+        String responseType = clientSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+        if (responseType == null) {
+            responseType = "code";
+        }
+        String respMode = clientSession.getNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+        OIDCResponseMode responseMode = OIDCResponseMode.parse(respMode, OIDCResponseType.parse(responseType));
+
         event.event(EventType.LOGIN).client(clientSession.getClient())
-                .user(clientSession.getUserSession().getUser())
-                .session(clientSession.getUserSession().getId())
+                .user(userSession.getUser())
+                .session(userSession.getId())
                 .detail(Details.CODE_ID, clientSession.getId())
                 .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
                 .detail(Details.USERNAME, clientSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME))
-                .detail(Details.RESPONSE_TYPE, "code");
-
-        UserSessionModel userSession = clientSession.getUserSession();
-
-        if (userSession != null) {
-            event.detail(Details.AUTH_METHOD, userSession.getAuthMethod());
-            event.detail(Details.USERNAME, userSession.getLoginUsername());
-            if (userSession.isRememberMe()) {
-                event.detail(Details.REMEMBER_ME, "true");
-            }
+                .detail(Details.AUTH_METHOD, userSession.getAuthMethod())
+                .detail(Details.USERNAME, userSession.getLoginUsername())
+                .detail(Details.RESPONSE_TYPE, responseType)
+                .detail(Details.RESPONSE_MODE, responseMode.toString().toLowerCase());
+        if (userSession.isRememberMe()) {
+            event.detail(Details.REMEMBER_ME, "true");
         }
     }
 
@@ -827,9 +824,14 @@ public class LoginActionsService {
             LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, context.getClientSession().getAuthMethod());
             protocol.setRealm(context.getRealm())
                     .setHttpHeaders(context.getHttpRequest().getHttpHeaders())
-                    .setUriInfo(context.getUriInfo());
-            event.detail(Details.CUSTOM_REQUIRED_ACTION, action).error(Errors.REJECTED_BY_USER);
-            return protocol.sendError(context.getClientSession(), Error.CONSENT_DENIED);
+                    .setUriInfo(context.getUriInfo())
+                    .setEventBuilder(event);
+
+            event.detail(Details.CUSTOM_REQUIRED_ACTION, action);
+            Response response = protocol.sendError(context.getClientSession(), Error.CONSENT_DENIED);
+            event.error(Errors.REJECTED_BY_USER);
+            return response;
+
         }
 
         throw new RuntimeException("Unreachable");
diff --git a/services/src/test/java/org/keycloak/test/ResponseTypeTest.java b/services/src/test/java/org/keycloak/test/ResponseTypeTest.java
new file mode 100644
index 0000000..b3f77a7
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/ResponseTypeTest.java
@@ -0,0 +1,41 @@
+package org.keycloak.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ResponseTypeTest {
+
+    @Test
+    public void testResponseTypes() {
+        assertFail(null);
+        assertFail("");
+        assertFail("foo");
+        assertSuccess("code");
+        assertSuccess("none");
+        assertFail("id_token");
+        assertFail("token");
+        assertFail("refresh_token");
+        assertSuccess("id_token token");
+        assertSuccess("code token");
+        assertSuccess("code id_token");
+        assertSuccess("code id_token token");
+        assertFail("code none");
+        assertFail("code refresh_token");
+    }
+
+    private void assertSuccess(String responseType) {
+        OIDCResponseType.parse(responseType);
+    }
+
+    private void assertFail(String responseType) {
+        try {
+            OIDCResponseType.parse(responseType);
+            Assert.fail("Not expected to parse '" + responseType + "' with success");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+}
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 9e51065..8147cb3 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
@@ -255,6 +255,7 @@ public class AdminAPITest {
             Assert.assertEquals(rep.getAccessCodeLifespanUserAction(), storedRealm.getAccessCodeLifespanUserAction());
         if (rep.getNotBefore() != null) Assert.assertEquals(rep.getNotBefore(), storedRealm.getNotBefore());
         if (rep.getAccessTokenLifespan() != null) Assert.assertEquals(rep.getAccessTokenLifespan(), storedRealm.getAccessTokenLifespan());
+        if (rep.getAccessTokenLifespanForImplicitFlow() != null) Assert.assertEquals(rep.getAccessTokenLifespanForImplicitFlow(), storedRealm.getAccessTokenLifespanForImplicitFlow());
         if (rep.getSsoSessionIdleTimeout() != null) Assert.assertEquals(rep.getSsoSessionIdleTimeout(), storedRealm.getSsoSessionIdleTimeout());
         if (rep.getSsoSessionMaxLifespan() != null) Assert.assertEquals(rep.getSsoSessionMaxLifespan(), storedRealm.getSsoSessionMaxLifespan());
         if (rep.getRequiredCredentials() != null) {
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 74c70ea..84e724b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -8,6 +8,7 @@ import org.junit.Assert;
 import org.junit.rules.TestRule;
 import org.junit.runners.model.Statement;
 import org.keycloak.Config;
+import org.keycloak.OAuth2Constants;
 import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
 import org.keycloak.common.constants.ServiceAccountConstants;
 import org.keycloak.events.admin.AdminEvent;
@@ -134,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, ServiceAccountConstants.CLIENT_AUTH)
+                .detail(Details.RESPONSE_TYPE, OAuth2Constants.CLIENT_CREDENTIALS)
                 .removeDetail(Details.CODE_ID)
                 .session(isUUID());
     }
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 f704553..4690308 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
@@ -218,7 +218,7 @@ public class CustomFlowTest {
                 .client(clientId)
                 .user(userId)
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_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/GroupTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/GroupTest.java
index 97250c4..a5f2388 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
@@ -7,6 +7,7 @@ import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
+import org.keycloak.OAuth2Constants;
 import org.keycloak.admin.client.Keycloak;
 import org.keycloak.admin.client.resource.GroupResource;
 import org.keycloak.admin.client.resource.RealmResource;
@@ -256,7 +257,7 @@ public class GroupTest {
                 .client(clientId)
                 .user(userId)
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_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 b2d14b9..99e5b95 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
@@ -74,6 +74,7 @@ public class ImportTest extends AbstractModelTest {
     public static void assertDataImportedInRealm(KeycloakSession session, RealmModel realm) {
         Assert.assertTrue(realm.isVerifyEmail());
         Assert.assertEquals(3600000, realm.getOfflineSessionIdleTimeout());
+        Assert.assertEquals(1500, realm.getAccessTokenLifespanForImplicitFlow());
 
         List<RequiredCredentialModel> creds = realm.getRequiredCredentials();
         Assert.assertEquals(1, creds.size());
@@ -327,6 +328,13 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertFalse(otherAppAdminConsent.isRoleGranted(application.getRole("app-admin")));
         Assert.assertTrue(otherAppAdminConsent.isProtocolMapperGranted(gssCredentialMapper));
 
+        Assert.assertTrue(application.isStandardFlowEnabled());
+        Assert.assertTrue(application.isImplicitFlowEnabled());
+        Assert.assertTrue(application.isDirectAccessGrantsEnabled());
+        Assert.assertFalse(otherApp.isStandardFlowEnabled());
+        Assert.assertFalse(otherApp.isImplicitFlowEnabled());
+        Assert.assertFalse(otherApp.isDirectAccessGrantsEnabled());
+
         // Test service accounts
         Assert.assertFalse(application.isServiceAccountsEnabled());
         Assert.assertTrue(otherApp.isServiceAccountsEnabled());
@@ -344,6 +352,7 @@ public class ImportTest extends AbstractModelTest {
         RealmModel realm =manager.importRealm(rep);
 
         Assert.assertEquals(600, realm.getAccessCodeLifespanUserAction());
+        Assert.assertEquals(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT, realm.getAccessTokenLifespanForImplicitFlow());
         Assert.assertEquals(Constants.DEFAULT_OFFLINE_SESSION_IDLE_TIMEOUT, realm.getOfflineSessionIdleTimeout());
         verifyRequiredCredentials(realm.getRequiredCredentials(), "password");
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
index d3a47e0..5d5e0ed 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -30,6 +30,7 @@ import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.models.Constants;
 import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.AssertEvents;
@@ -160,12 +161,21 @@ public class AuthorizationCodeTest {
     }
 
     @Test
+    public void authorizationRequestImplicitFlowDisabled() throws IOException {
+        UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
+        b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "token id_token");
+        driver.navigate().to(b.build().toURL());
+        assertEquals("Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.", errorPage.getError());
+        events.expectLogin().error(Errors.NOT_ALLOWED).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "token id_token").assertEvent();
+    }
+
+    @Test
     public void authorizationRequestInvalidResponseType() throws IOException {
         UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
         b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "token");
         driver.navigate().to(b.build().toURL());
         assertEquals("Invalid parameter: response_type", errorPage.getError());
-        events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "token").assertEvent();
+        events.expectLogin().error(Errors.INVALID_REQUEST).client((String) null).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "token").assertEvent();
     }
 
     private void assertCode(String expectedCodeId, String actualCode) {
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 537a297..898066a 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
@@ -189,7 +189,7 @@ public class ClientAuthSignedJWTTest {
         events.expectLogin()
                 .client("client2")
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_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/OAuthRedirectUriTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
index 6c205ad..d333f86 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
@@ -40,6 +40,7 @@ import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
 import java.io.IOException;
+import java.net.URL;
 
 /**
  * @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
@@ -174,7 +175,10 @@ public class OAuthRedirectUriTest {
         OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertNotNull(response.getCode());
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/app?code="));
+        URL url = new URL(driver.getCurrentUrl());
+        Assert.assertTrue(url.toString().startsWith("http://localhost:8081/app"));
+        Assert.assertTrue(url.getQuery().contains("code="));
+        Assert.assertTrue(url.getQuery().contains("state="));
     }
 
     @Test
@@ -192,7 +196,11 @@ public class OAuthRedirectUriTest {
         OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertNotNull(response.getCode());
-        Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/app?key=value&code="));
+        URL url = new URL(driver.getCurrentUrl());
+        Assert.assertTrue(url.toString().startsWith("http://localhost:8081/app"));
+        Assert.assertTrue(url.getQuery().contains("key=value"));
+        Assert.assertTrue(url.getQuery().contains("state="));
+        Assert.assertTrue(url.getQuery().contains("code="));
     }
 
     @Test
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 884d9f0..a4b2855 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
@@ -319,7 +319,7 @@ public class OfflineTokenTest {
                 .client("offline-client")
                 .user(userId)
                 .session(token.getSessionState())
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_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 +361,7 @@ public class OfflineTokenTest {
                 .client("offline-client")
                 .user(userId)
                 .session(token.getSessionState())
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_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/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
index 74e3d38..b64a683 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
@@ -6,6 +6,7 @@ import org.apache.http.impl.client.DefaultHttpClient;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
+import org.keycloak.OAuth2Constants;
 import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
@@ -93,7 +94,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .client(clientId)
                 .user(userId)
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .detail(Details.USERNAME, login)
@@ -129,7 +130,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
         events.expectLogin()
                 .client("resource-owner")
                 .session(accessToken.getSessionState())
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.TOKEN_ID, accessToken.getId())
                 .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
                 .removeDetail(Details.CODE_ID)
@@ -285,7 +286,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
         events.expectLogin()
                 .client("resource-owner")
                 .session((String) null)
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
                 .removeDetail(Details.CONSENT)
@@ -307,7 +308,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
                 .client("resource-owner")
                 .user((String) null)
                 .session((String) null)
-                .detail(Details.RESPONSE_TYPE, "token")
+                .detail(Details.RESPONSE_TYPE, OAuth2Constants.PASSWORD)
                 .detail(Details.USERNAME, "invalid")
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json
index 68ec4d3..af86592 100755
--- a/testsuite/integration/src/test/resources/model/testrealm.json
+++ b/testsuite/integration/src/test/resources/model/testrealm.json
@@ -2,6 +2,7 @@
     "realm": "test-realm",
     "enabled": true,
     "accessTokenLifespan": 6000,
+    "accessTokenLifespanForImplicitFlow": 1500,
     "accessCodeLifespan": 30,
     "accessCodeLifespanUserAction": 600,
     "offlineSessionIdleTimeout": 3600000,
@@ -154,6 +155,7 @@
             "clientId": "Application",
             "name": "Applicationn",
             "enabled": true,
+            "implicitFlowEnabled": true,
             "nodeReRegistrationTimeout": 50,
             "registeredNodes": {
                 "node1": 10,
@@ -164,6 +166,8 @@
             "clientId": "OtherApp",
             "name": "Other Application",
             "enabled": true,
+            "standardFlowEnabled": false,
+            "directAccessGrantsEnabled": false,
             "serviceAccountsEnabled": true,
             "clientAuthenticatorType": "client-jwt",
             "protocolMappers" : [
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
index 87eadb5..2be0435 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/clients/CreateClientForm.java
@@ -32,8 +32,14 @@ public class CreateClientForm extends Form {
     @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='consentRequired']]")
     private OnOffSwitch consentRequiredSwitch;
 
-    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='directGrantsOnly']]")
-    private OnOffSwitch directGrantsOnlySwitch;
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='standardFlowEnabled']]")
+    private OnOffSwitch standardFlowEnabledSwitch;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='implicitFlowEnabled']]")
+    private OnOffSwitch implicitFlowEnabledSwitch;
+
+    @FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='directAccessGrantsEnabled']]")
+    private OnOffSwitch directAccessGrantsEnabledSwitch;
 
     @FindBy(id = "protocol")
     private Select protocolSelect;
@@ -69,7 +75,9 @@ public class CreateClientForm extends Form {
         setName(client.getName());
         setEnabled(client.isEnabled());
         setConsentRequired(client.isConsentRequired());
-        setDirectGrantsOnly(client.isDirectGrantsOnly());
+        setStandardFlowEnabled(client.isStandardFlowEnabled());
+        setImplicitFlowEnabled(client.isImplicitFlowEnabled());
+        setDirectAccessGrantsEnabled(client.isDirectAccessGrantsEnabled());
         setProtocol(client.getProtocol());
         if (OIDC.equals(client.getProtocol())) {
             setAccessType(client);
@@ -88,7 +96,9 @@ public class CreateClientForm extends Form {
         values.setName(getName());
         values.setEnabled(isEnabled());
         values.setConsentRequired(isConsentRequired());
-        values.setDirectGrantsOnly(isDirectGrantsOnly());
+        values.setStandardFlowEnabled(isStandardFlowEnabled());
+        values.setImplicitFlowEnabled(isImplicitFlowEnabled());
+        values.setDirectAccessGrantsEnabled(isDirectAccessGrantsEnabled());
         values.setProtocol(getProtocol());
         if (OIDC.equals(values.getProtocol())) {
             values.setBearerOnly(isBearerOnly());
@@ -195,12 +205,28 @@ public class CreateClientForm extends Form {
         consentRequiredSwitch.setOn(consentRequired);
     }
 
-    public boolean isDirectGrantsOnly() {
-        return directGrantsOnlySwitch.isOn();
+    public boolean isStandardFlowEnabled() {
+        return standardFlowEnabledSwitch.isOn();
+    }
+
+    public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+        standardFlowEnabledSwitch.setOn(standardFlowEnabled);
+    }
+
+    public boolean isImplicitFlowEnabled() {
+        return implicitFlowEnabledSwitch.isOn();
+    }
+
+    public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+        implicitFlowEnabledSwitch.setOn(implicitFlowEnabled);
+    }
+
+    public boolean isDirectAccessGrantsEnabled() {
+        return directAccessGrantsEnabledSwitch.isOn();
     }
 
-    public void setDirectGrantsOnly(boolean directGrantsOnly) {
-        directGrantsOnlySwitch.setOn(directGrantsOnly);
+    public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+        directAccessGrantsEnabledSwitch.setOn(directAccessGrantsEnabled);
     }
 
     public String getProtocol() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
index 6c40d64..94e9b4b 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
@@ -56,7 +56,9 @@ public abstract class AbstractClientTest extends AbstractConsoleTest {
         client.setClientId(clientId);
         client.setEnabled(true);
         client.setConsentRequired(false);
-        client.setDirectGrantsOnly(false);
+        client.setStandardFlowEnabled(true);
+        client.setImplicitFlowEnabled(false);
+        client.setDirectAccessGrantsEnabled(true);
         
         client.setProtocol(OIDC);
         
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
index 5229527..d259adf 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/clients/ClientSettingsTest.java
@@ -111,7 +111,9 @@ public class ClientSettingsTest extends AbstractClientTest {
         assertEqualsStringAttributes(c1.getName(), c2.getName());
         assertEqualsBooleanAttributes(c1.isEnabled(), c2.isEnabled());
         assertEqualsBooleanAttributes(c1.isConsentRequired(), c2.isConsentRequired());
-        assertEqualsBooleanAttributes(c1.isDirectGrantsOnly(), c2.isDirectGrantsOnly());
+        assertEqualsBooleanAttributes(c1.isStandardFlowEnabled(), c2.isStandardFlowEnabled());
+        assertEqualsBooleanAttributes(c1.isImplicitFlowEnabled(), c2.isImplicitFlowEnabled());
+        assertEqualsBooleanAttributes(c1.isDirectAccessGrantsEnabled(), c2.isDirectAccessGrantsEnabled());
         assertEqualsStringAttributes(c1.getProtocol(), c2.getProtocol());
 
         assertEqualsBooleanAttributes(c1.isBearerOnly(), c2.isBearerOnly());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
index b43bfad..5174acf 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
@@ -55,7 +55,7 @@ public class LoginEventsTest extends AbstractConsoleTest {
 
         List<WebElement> resultList = loginEventsPage.table().rows();
 
-        assertEquals(7, resultList.size());
+        assertEquals(8, resultList.size());
         resultList.get(0).findElement(By.xpath("//td[text()='LOGIN']"));
         resultList.get(0).findElement(By.xpath("//td[text()='User']/../td[text()='" + testUser.getId() + "']"));
         resultList.get(0).findElement(By.xpath("//td[text()='Client']/../td[text()='security-admin-console']"));