keycloak-aplcache

Changes

Details

diff --git a/core/src/main/java/org/keycloak/representations/RefreshToken.java b/core/src/main/java/org/keycloak/representations/RefreshToken.java
index ff1ce68..39c7c46 100755
--- a/core/src/main/java/org/keycloak/representations/RefreshToken.java
+++ b/core/src/main/java/org/keycloak/representations/RefreshToken.java
@@ -1,7 +1,6 @@
 package org.keycloak.representations;
 
-import org.codehaus.jackson.annotate.JsonProperty;
-import org.keycloak.util.RefreshTokenUtil;
+import org.keycloak.util.TokenUtil;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -13,7 +12,7 @@ import java.util.Map;
 public class RefreshToken extends AccessToken {
 
     private RefreshToken() {
-        type(RefreshTokenUtil.TOKEN_TYPE_REFRESH);
+        type(TokenUtil.TOKEN_TYPE_REFRESH);
     }
 
     /**
diff --git a/core/src/main/java/org/keycloak/RSATokenVerifier.java b/core/src/main/java/org/keycloak/RSATokenVerifier.java
index 9bd544d..80a4cd6 100755
--- a/core/src/main/java/org/keycloak/RSATokenVerifier.java
+++ b/core/src/main/java/org/keycloak/RSATokenVerifier.java
@@ -3,6 +3,7 @@ package org.keycloak;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.representations.AccessToken;
+import org.keycloak.util.TokenUtil;
 
 import java.io.IOException;
 import java.security.PublicKey;
@@ -13,10 +14,10 @@ import java.security.PublicKey;
  */
 public class RSATokenVerifier {
     public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl) throws VerificationException {
-        return verifyToken(tokenString, realmKey, realmUrl, true);
+        return verifyToken(tokenString, realmKey, realmUrl, true, true);
     }
 
-    public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl, boolean checkActive) throws VerificationException {
+    public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl, boolean checkActive, boolean checkTokenType) throws VerificationException {
         JWSInput input = null;
         try {
             input = new JWSInput(tokenString);
@@ -42,6 +43,13 @@ public class RSATokenVerifier {
             throw new VerificationException("Token audience doesn't match domain. Token issuer is " + token.getIssuer() + ", but URL from configuration is " + realmUrl);
 
         }
+
+        if (checkTokenType) {
+            String type = token.getType();
+            if (type == null || !type.equalsIgnoreCase(TokenUtil.TOKEN_TYPE_BEARER)) {
+                throw new VerificationException("Token type is incorrect. Expected '" + TokenUtil.TOKEN_TYPE_BEARER + "' but was '" + type + "'");
+            }
+        }
         if (checkActive && !token.isActive()) {
             throw new VerificationException("Token is not active.");
         }
diff --git a/core/src/test/java/org/keycloak/RSAVerifierTest.java b/core/src/test/java/org/keycloak/RSAVerifierTest.java
index e1eb846..acdbb32 100755
--- a/core/src/test/java/org/keycloak/RSAVerifierTest.java
+++ b/core/src/test/java/org/keycloak/RSAVerifierTest.java
@@ -10,6 +10,7 @@ import org.junit.Test;
 import org.keycloak.jose.jws.JWSBuilder;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.util.Time;
+import org.keycloak.util.TokenUtil;
 
 import javax.security.auth.x500.X500Principal;
 import java.io.IOException;
@@ -71,7 +72,8 @@ public class RSAVerifierTest {
     public void initTest() {
 
         token = new AccessToken();
-        token.subject("CN=Client")
+        token.type(TokenUtil.TOKEN_TYPE_BEARER)
+                .subject("CN=Client")
                 .issuer("http://localhost:8080/auth/realm")
                 .addAccess("service").addRole("admin");
     }
diff --git a/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java b/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
index b233574..354a778 100644
--- a/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
+++ b/examples/demo-template/offline-access-app/src/main/java/org/keycloak/example/OfflineAccessPortalServlet.java
@@ -3,7 +3,6 @@ package org.keycloak.example;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
 import javax.security.cert.X509Certificate;
@@ -22,12 +21,10 @@ import org.keycloak.adapters.HttpFacade;
 import org.keycloak.adapters.KeycloakDeployment;
 import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
 import org.keycloak.adapters.ServerRequest;
-import org.keycloak.constants.ServiceUrlConstants;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.util.JsonSerialization;
-import org.keycloak.util.KeycloakUriBuilder;
-import org.keycloak.util.RefreshTokenUtil;
+import org.keycloak.util.TokenUtil;
 import org.keycloak.util.StreamUtil;
 import org.keycloak.util.Time;
 import org.keycloak.util.UriUtils;
@@ -64,7 +61,7 @@ public class OfflineAccessPortalServlet extends HttpServlet {
             refreshTokenInfo = "No token saved in database. Please login first";
             savedTokenAvailable = false;
         } else {
-            RefreshToken refreshTokenDecoded = RefreshTokenUtil.getRefreshToken(refreshToken);
+            RefreshToken refreshTokenDecoded = TokenUtil.getRefreshToken(refreshToken);
             String exp = (refreshTokenDecoded.getExpiration() == 0) ? "NEVER" : Time.toDate(refreshTokenDecoded.getExpiration()).toString();
             refreshTokenInfo = String.format("<p>Type: %s</p><p>ID: %s</p><p>Expires: %s</p>", refreshTokenDecoded.getType(), refreshTokenDecoded.getId(), exp);
             savedTokenAvailable = true;
@@ -89,8 +86,8 @@ public class OfflineAccessPortalServlet extends HttpServlet {
 
         RefreshTokenDAO.saveToken(refreshToken);
 
-        RefreshToken refreshTokenDecoded = RefreshTokenUtil.getRefreshToken(refreshToken);
-        Boolean isOfflineToken = refreshTokenDecoded.getType().equals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+        RefreshToken refreshTokenDecoded = TokenUtil.getRefreshToken(refreshToken);
+        Boolean isOfflineToken = refreshTokenDecoded.getType().equals(TokenUtil.TOKEN_TYPE_OFFLINE);
         req.setAttribute("isOfflineToken", isOfflineToken);
     }
 
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
index a965325..8af3ef8 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -1535,12 +1535,13 @@ module.directive('onoffswitchstring', function() {
 });
 
 /**
- * Directive for presenting an ON-OFF switch for checkbox.
+ * Directive for presenting an ON-OFF switch for checkbox. The directive expects the true-value or false-value to be string like 'true' or 'false', not boolean true/false.
  * This directive provides some additional capabilities to the default onoffswitch such as:
  *
- * - Specific scope to specify the value. Instead of just true or false.
+ * - Specific scope to specify the value. Instead of just 'true' or 'false' you can use any other values. For example: true-value="'foo'" false-value="'bar'" .
+ * But 'true'/'false' are defaults if true-value and false-value are not specified
  *
- * Usage: <input ng-model="mmm" name="nnn" id="iii" onoffswitchvalue [on-text="ooo" off-text="fff"] />
+ * Usage: <input ng-model="mmm" name="nnn" id="iii" onoffswitchvalue [ true-value="'true'" false-value="'false'" on-text="ooo" off-text="fff"] />
  */
 module.directive('onoffswitchvalue', function() {
     return {
@@ -1549,7 +1550,8 @@ module.directive('onoffswitchvalue', function() {
         scope: {
             name: '@',
             id: '@',
-            value: '=',
+            trueValue: '@',
+            falseValue: '@',
             ngModel: '=',
             ngDisabled: '=',
             kcOnText: '@onText',
@@ -1557,7 +1559,7 @@ module.directive('onoffswitchvalue', function() {
         },
         // TODO - The same code acts differently when put into the templateURL. Find why and move the code there.
         //templateUrl: "templates/kc-switch.html",
-        template: "<span><div class='onoffswitch' tabindex='0'><input type='checkbox' ng-true-value='{{value}}' ng-model='ngModel' ng-disabled='ngDisabled' class='onoffswitch-checkbox' name='{{name}}' id='{{id}}'><label for='{{id}}' class='onoffswitch-label'><span class='onoffswitch-inner'><span class='onoffswitch-active'>{{kcOnText}}</span><span class='onoffswitch-inactive'>{{kcOffText}}</span></span><span class='onoffswitch-switch'></span></label></div></span>",
+        template: "<span><div class='onoffswitch' tabindex='0'><input type='checkbox' ng-true-value='{{trueValue}}' ng-false-value='{{falseValue}}' ng-model='ngModel' ng-disabled='ngDisabled' class='onoffswitch-checkbox' name='{{name}}' id='{{id}}'><label for='{{id}}' class='onoffswitch-label'><span class='onoffswitch-inner'><span class='onoffswitch-active'>{{kcOnText}}</span><span class='onoffswitch-inactive'>{{kcOffText}}</span></span><span class='onoffswitch-switch'></span></label></div></span>",
         compile: function(element, attrs) {
             /*
              We don't want to propagate basic attributes to the root element of directive. Id should be passed to the
@@ -1566,6 +1568,9 @@ module.directive('onoffswitchvalue', function() {
             element.removeAttr('name');
             element.removeAttr('id');
 
+            if (!attrs.trueValue) { attrs.trueValue = "'true'"; }
+            if (!attrs.falseValue) { attrs.falseValue = "'false'"; }
+
             if (!attrs.onText) { attrs.onText = "ON"; }
             if (!attrs.offText) { attrs.offText = "OFF"; }
 
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-offline-sessions.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-offline-sessions.html
index c8afb02..a5df7b6 100644
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-offline-sessions.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-offline-sessions.html
@@ -14,7 +14,7 @@
                 <div class="col-md-6">
                     <input class="form-control" type="text" id="activeSessions" name="activeSessions" data-ng-model="count" ng-disabled="true">
                 </div>
-                <kc-tooltip>Total number of active offline tokens for this client.</kc-tooltip>
+                <kc-tooltip>Total number of offline tokens for this client.</kc-tooltip>
             </div>
         </fieldset>
     </form>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
index 4654a58..f372622 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
@@ -106,7 +106,7 @@
                     <div class="form-group">
                         <label class="col-sm-2 control-label" for="backchannelSupported">Backchannel Logout</label>
                         <div class="col-sm-4">
-                            <input ng-model="identityProvider.config.backchannelSupported" id="backchannelSupported" value="'true'" onoffswitchvalue />
+                            <input ng-model="identityProvider.config.backchannelSupported" id="backchannelSupported" onoffswitchvalue />
                         </div>
                         <span tooltip-trigger="mouseover mouseout" tooltip-placement="right" tooltip="Does the external IDP support backchannel logout?" class="fa fa-info-circle"></span>
                     </div>
@@ -166,7 +166,7 @@
             <div class="form-group">
                 <label class="col-md-2 control-label" for="validateSignature">Validate Signatures</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.config.validateSignature" id="validateSignature" value="'true'" onoffswitchvalue />
+                    <input ng-model="identityProvider.config.validateSignature" id="validateSignature" onoffswitchvalue />
                 </div>
                 <kc-tooltip>Enable/disable signature validation of external IDP signatures.</kc-tooltip>
             </div>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 5387826..478137c 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -100,7 +100,7 @@
                     <div class="form-group">
                         <label class="col-sm-2 control-label" for="backchannelSupported">Backchannel Logout</label>
                         <div class="col-sm-4">
-                            <input ng-model="identityProvider.config.backchannelSupported" id="backchannelSupported" value="'true'" onoffswitchvalue />
+                            <input ng-model="identityProvider.config.backchannelSupported" id="backchannelSupported" onoffswitchvalue />
                         </div>
                         <span tooltip-trigger="mouseover mouseout" tooltip-placement="right" tooltip="Does the external IDP support backchannel logout?" class="fa fa-info-circle"></span>
                     </div>
@@ -117,21 +117,21 @@
             <div class="form-group">
                 <label class="col-md-2 control-label" for="postBindingResponse">HTTP-POST Binding Response</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.config.postBindingResponse" id="postBindingResponse" value="'true'" onoffswitchvalue />
+                    <input ng-model="identityProvider.config.postBindingResponse" id="postBindingResponse" onoffswitchvalue />
                 </div>
                 <kc-tooltip>Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.</kc-tooltip>
             </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="postBindingAuthnRequest">HTTP-POST Binding for AuthnRequest</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.config.postBindingAuthnRequest" id="postBindingAuthnRequest" value="'true'" onoffswitchvalue />
+                    <input ng-model="identityProvider.config.postBindingAuthnRequest" id="postBindingAuthnRequest" onoffswitchvalue />
                 </div>
                 <kc-tooltip>Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.</kc-tooltip>
             </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="wantAuthnRequestsSigned">Want AuthnRequests Signed</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.config.wantAuthnRequestsSigned" id="wantAuthnRequestsSigned" name="wantAuthnRequestsSigned" value="'true'" onoffswitchvalue />
+                    <input ng-model="identityProvider.config.wantAuthnRequestsSigned" id="wantAuthnRequestsSigned" name="wantAuthnRequestsSigned" onoffswitchvalue />
                 </div>
                 <kc-tooltip> Indicates whether the identity provider expects signed a AuthnRequest.</kc-tooltip>
             </div>
@@ -150,14 +150,14 @@
             <div class="form-group">
                 <label class="col-md-2 control-label" for="forceAuthn">Force Authentication</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.config.forceAuthn" id="forceAuthn" name="forceAuthn" value="'true'" onoffswitchvalue />
+                    <input ng-model="identityProvider.config.forceAuthn" id="forceAuthn" name="forceAuthn" onoffswitchvalue />
                 </div>
                 <kc-tooltip> Indicates whether the identity provider must authenticate the presenter directly rather than rely on a previous security context.</kc-tooltip>
             </div>
             <div class="form-group">
                 <label class="col-md-2 control-label" for="validateSignature">Validate Signature</label>
                 <div class="col-md-6">
-                    <input ng-model="identityProvider.config.validateSignature" id="validateSignature" value="'true'" onoffswitchvalue />
+                    <input ng-model="identityProvider.config.validateSignature" id="validateSignature" onoffswitchvalue />
                 </div>
                 <kc-tooltip>Enable/disable signature validation of SAML responses.</kc-tooltip>
             </div>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
index f033aac..e16406d 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
@@ -29,7 +29,7 @@
         <li ng-class="{active: path[4] == 'offline-access'}" data-ng-show="!client.bearerOnly">
             <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/offline-access">Offline Access</a>
             <kc-tooltip>View offline sessions for this client.  Allows you to see which users retrieve offline token and when they retrieve it.
-                To revoke all tokens for the client, go to Revocation tab and set new not before value.
+                To revoke all tokens for the client, go to Revocation tab and set not before value to now.
             </kc-tooltip>
         </li>
 
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java
index 73d58bc..40604a4 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/CookieTokenStore.java
@@ -54,7 +54,7 @@ public class CookieTokenStore {
 
         try {
             // Skip check if token is active now. It's supposed to be done later by the caller
-            AccessToken accessToken = RSATokenVerifier.verifyToken(accessTokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl(), false);
+            AccessToken accessToken = RSATokenVerifier.verifyToken(accessTokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl(), false, true);
             IDToken idToken;
             if (idTokenString != null && idTokenString.length() > 0) {
                 JWSInput input = new JWSInput(idTokenString);
diff --git a/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java b/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
index 7ba3bb7..9c8c678 100755
--- a/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
+++ b/model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
@@ -1,5 +1,6 @@
 package org.keycloak.migration;
 
+import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.provider.Provider;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 
@@ -18,4 +19,6 @@ public interface MigrationProvider extends Provider {
      */
     List<ProtocolMapperRepresentation> getMappersForClaimMask(Long claimMask);
 
+    List<ProtocolMapperModel> getBuiltinMappers(String protocol);
+
 }
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java
index ecb5482..6712c08 100644
--- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java
@@ -2,13 +2,10 @@ package org.keycloak.migration.migrators;
 
 import java.util.List;
 
+import org.keycloak.Config;
+import org.keycloak.migration.MigrationProvider;
 import org.keycloak.migration.ModelVersion;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 /**
@@ -19,6 +16,20 @@ public class MigrateTo1_6_0 {
     public static final ModelVersion VERSION = new ModelVersion("1.6.0");
 
     public void migrate(KeycloakSession session) {
+        MigrationProvider provider = session.getProvider(MigrationProvider.class);
+
+        List<ProtocolMapperModel> builtinMappers = provider.getBuiltinMappers("openid-connect");
+        ProtocolMapperModel localeMapper = null;
+        for (ProtocolMapperModel m : builtinMappers) {
+            if (m.getName().equals("locale")) {
+                localeMapper = m;
+            }
+        }
+
+        if (localeMapper == null) {
+            throw new RuntimeException("Can't find default locale mapper");
+        }
+
         List<RealmModel> realms = session.realms().getRealms();
         for (RealmModel realm : realms) {
             if (realm.getRole(Constants.OFFLINE_ACCESS_ROLE) == null) {
@@ -39,8 +50,12 @@ public class MigrateTo1_6_0 {
                     user.grantRole(role);
                 }
             }
-        }
 
+            ClientModel adminConsoleClient = realm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
+            if (adminConsoleClient != null) {
+                adminConsoleClient.addProtocolMapper(localeMapper);
+            }
+        }
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
index 71c30e4..096252a 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
@@ -119,7 +119,7 @@ public class UserInfoEndpoint {
 
         AccessToken token = null;
         try {
-            token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), true);
+            token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), true, true);
         } catch (VerificationException e) {
             throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Token invalid: " + e.getMessage(), Status.FORBIDDEN);
         }
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 ee8e9e8..8716d73 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -33,7 +33,7 @@ import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.offline.OfflineTokenUtils;
-import org.keycloak.util.RefreshTokenUtil;
+import org.keycloak.util.TokenUtil;
 import org.keycloak.util.Time;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -96,7 +96,7 @@ public class TokenManager {
 
         UserSessionModel userSession = null;
         ClientSessionModel clientSession = null;
-        if (RefreshTokenUtil.TOKEN_TYPE_OFFLINE.equals(oldToken.getType())) {
+        if (TokenUtil.TOKEN_TYPE_OFFLINE.equals(oldToken.getType())) {
 
             clientSession = OfflineTokenUtils.findOfflineClientSession(session, realm, user, oldToken.getClientSession(), oldToken.getSessionState());
             if (clientSession != null) {
@@ -168,12 +168,12 @@ public class TokenManager {
                 .generateIDToken();
 
         // Don't generate refresh token again if refresh was triggered with offline token
-        if (!refreshToken.getType().equals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE)) {
+        if (!refreshToken.getType().equals(TokenUtil.TOKEN_TYPE_OFFLINE)) {
             responseBuilder.generateRefreshToken();
         }
 
         AccessTokenResponse res = responseBuilder.build();
-        return new RefreshResult(res, RefreshTokenUtil.TOKEN_TYPE_OFFLINE.equals(refreshToken.getType()));
+        return new RefreshResult(res, TokenUtil.TOKEN_TYPE_OFFLINE.equals(refreshToken.getType()));
     }
 
     public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken) throws OAuthErrorException {
@@ -385,6 +385,7 @@ public class TokenManager {
         AccessToken token = new AccessToken();
         if (clientSession != null) token.clientSession(clientSession.getId());
         token.id(KeycloakModelUtils.generateId());
+        token.type(TokenUtil.TOKEN_TYPE_BEARER);
         token.subject(user.getId());
         token.audience(client.getClientId());
         token.issuedNow();
@@ -487,7 +488,7 @@ public class TokenManager {
             }
 
             String scopeParam = clientSession.getNote(OIDCLoginProtocol.SCOPE_PARAM);
-            boolean offlineTokenRequested = RefreshTokenUtil.isOfflineTokenRequested(scopeParam);
+            boolean offlineTokenRequested = TokenUtil.isOfflineTokenRequested(scopeParam);
             if (offlineTokenRequested) {
                 if (!OfflineTokenUtils.isOfflineTokenAllowed(realm, clientSession)) {
                     event.error(Errors.NOT_ALLOWED);
@@ -495,7 +496,7 @@ public class TokenManager {
                 }
 
                 refreshToken = new RefreshToken(accessToken);
-                refreshToken.type(RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+                refreshToken.type(TokenUtil.TOKEN_TYPE_OFFLINE);
                 OfflineTokenUtils.persistOfflineSession(session, realm, clientSession, userSession);
             } else {
                 refreshToken = new RefreshToken(accessToken);
@@ -512,6 +513,7 @@ public class TokenManager {
             }
             idToken = new IDToken();
             idToken.id(KeycloakModelUtils.generateId());
+            idToken.type(TokenUtil.TOKEN_TYPE_ID);
             idToken.subject(accessToken.getSubject());
             idToken.audience(client.getClientId());
             idToken.issuedNow();
diff --git a/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java b/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java
index 457388b..0156fb6 100755
--- a/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java
@@ -42,7 +42,7 @@ public class AppAuthManager extends AuthenticationManager {
     public AuthResult authenticateBearerToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
         String tokenString = extractAuthorizationHeaderToken(headers);
         if (tokenString == null) return null;
-        AuthResult authResult = verifyIdentityToken(session, realm, uriInfo, connection, true, tokenString, headers);
+        AuthResult authResult = verifyIdentityToken(session, realm, uriInfo, connection, true, true, tokenString, headers);
         return authResult;
     }
 
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 5f1f9bf..73d274e 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -68,6 +68,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 import org.keycloak.freemarker.LocaleHelper;
+import org.keycloak.util.TokenUtil;
 
 /**
  * Stateless object that manages authentication
@@ -115,7 +116,7 @@ public class AuthenticationManager {
             Cookie cookie = headers.getCookies().get(KEYCLOAK_IDENTITY_COOKIE);
             if (cookie == null) return;
             String tokenString = cookie.getValue();
-            AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), false);
+            AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), false, false);
             UserSessionModel cookieSession = session.sessions().getUserSession(realm, token.getSessionState());
             if (cookieSession == null || !cookieSession.getId().equals(userSession.getId())) return;
             expireIdentityCookie(realm, uriInfo, connection);
@@ -383,7 +384,7 @@ public class AuthenticationManager {
         }
 
         String tokenString = cookie.getValue();
-        AuthResult authResult = verifyIdentityToken(session, realm, session.getContext().getUri(), session.getContext().getConnection(), checkActive, tokenString, session.getContext().getRequestHeaders());
+        AuthResult authResult = verifyIdentityToken(session, realm, session.getContext().getUri(), session.getContext().getConnection(), checkActive, false, tokenString, session.getContext().getRequestHeaders());
         if (authResult == null) {
             expireIdentityCookie(realm, session.getContext().getUri(), session.getContext().getConnection());
             return null;
@@ -601,9 +602,10 @@ public class AuthenticationManager {
     }
 
 
-    protected static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, String tokenString, HttpHeaders headers) {
+    protected static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, boolean checkTokenType,
+                                                    String tokenString, HttpHeaders headers) {
         try {
-            AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), checkActive);
+            AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), checkActive, checkTokenType);
             if (checkActive) {
                 if (!token.isActive() || token.getIssuedAt() < realm.getNotBefore()) {
                     logger.debug("identity cookie expired");
diff --git a/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java b/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java
index 22623f8..ad46afe 100644
--- a/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/migration/DefaultMigrationProvider.java
@@ -54,6 +54,12 @@ public class DefaultMigrationProvider implements MigrationProvider {
     }
 
     @Override
+    public List<ProtocolMapperModel> getBuiltinMappers(String protocol) {
+        LoginProtocolFactory providerFactory = (LoginProtocolFactory) session.getKeycloakSessionFactory().getProviderFactory(LoginProtocol.class, protocol);
+        return providerFactory.getBuiltinMappers();
+    }
+
+    @Override
     public void close() {
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CustomerServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CustomerServlet.java
index 9fa1a47..0b32146 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CustomerServlet.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CustomerServlet.java
@@ -2,6 +2,7 @@ package org.keycloak.testsuite.adapter;
 
 import org.junit.Assert;
 import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -44,6 +45,15 @@ public class CustomerServlet extends HttpServlet {
             Response response = target.request().get();
             Assert.assertEquals(401, response.getStatus());
             response.close();
+
+            // Assert not possible to authenticate with refresh token
+            RefreshableKeycloakSecurityContext refreshableContext = (RefreshableKeycloakSecurityContext) context;
+            response = target.request()
+                    .header(HttpHeaders.AUTHORIZATION, "Bearer " + refreshableContext.getRefreshToken())
+                    .get();
+            Assert.assertEquals(401, response.getStatus());
+            response.close();
+
             String html = target.request()
                                 .header(HttpHeaders.AUTHORIZATION, "Bearer " + context.getTokenString())
                                 .get(String.class);
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 77b6d19..cda71ac 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -9,7 +9,6 @@ import org.junit.rules.TestRule;
 import org.junit.runners.model.Statement;
 import org.keycloak.Config;
 import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
-import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
 import org.keycloak.constants.ServiceAccountConstants;
 import org.keycloak.events.admin.AdminEvent;
 import org.keycloak.events.Details;
@@ -24,13 +23,10 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
-import org.keycloak.protocol.oidc.endpoints.AuthorizationEndpoint;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
-import org.keycloak.util.RefreshTokenUtil;
+import org.keycloak.util.TokenUtil;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -157,7 +153,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
                 .detail(Details.CODE_ID, codeId)
                 .detail(Details.TOKEN_ID, isUUID())
                 .detail(Details.REFRESH_TOKEN_ID, isUUID())
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_REFRESH)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_REFRESH)
                 .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
                 .session(sessionId);
     }
@@ -166,7 +162,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
         return expect(EventType.REFRESH_TOKEN)
                 .detail(Details.TOKEN_ID, isUUID())
                 .detail(Details.REFRESH_TOKEN_ID, refreshTokenId)
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_REFRESH)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_REFRESH)
                 .detail(Details.UPDATED_REFRESH_TOKEN_ID, isUUID())
                 .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
                 .session(sessionId);
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 8eab300..a8c3d9c 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
@@ -43,7 +43,7 @@ import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.keycloak.util.JsonSerialization;
-import org.keycloak.util.RefreshTokenUtil;
+import org.keycloak.util.TokenUtil;
 import org.keycloak.util.Time;
 import org.keycloak.util.UriUtils;
 import org.openqa.selenium.WebDriver;
@@ -221,10 +221,10 @@ public class OfflineTokenTest {
 
         events.expectCodeToToken(codeId, sessionId)
                 .client("offline-client")
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
                 .assertEvent();
 
-        Assert.assertEquals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
+        Assert.assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
         Assert.assertEquals(0, offlineToken.getExpiration());
 
         testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, sessionId, userId);
@@ -278,7 +278,7 @@ public class OfflineTokenTest {
                 .client("offline-client")
                 .user(userId)
                 .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID)
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
                 .assertEvent();
         Assert.assertNotEquals(oldToken.getId(), refreshEvent.getDetails().get(Details.TOKEN_ID));
 
@@ -302,14 +302,14 @@ public class OfflineTokenTest {
                 .detail(Details.RESPONSE_TYPE, "token")
                 .detail(Details.TOKEN_ID, token.getId())
                 .detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
                 .detail(Details.USERNAME, "test-user@localhost")
                 .removeDetail(Details.CODE_ID)
                 .removeDetail(Details.REDIRECT_URI)
                 .removeDetail(Details.CONSENT)
                 .assertEvent();
 
-        Assert.assertEquals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
+        Assert.assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
         Assert.assertEquals(0, offlineToken.getExpiration());
 
         testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, token.getSessionState(), userId);
@@ -333,11 +333,11 @@ public class OfflineTokenTest {
                 .session(token.getSessionState())
                 .detail(Details.TOKEN_ID, token.getId())
                 .detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
                 .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "offline-client")
                 .assertEvent();
 
-        Assert.assertEquals(RefreshTokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
+        Assert.assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
         Assert.assertEquals(0, offlineToken.getExpiration());
 
         testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, token.getSessionState(), serviceAccountUserId);
@@ -356,7 +356,7 @@ public class OfflineTokenTest {
                 .session(token2.getSessionState())
                 .detail(Details.TOKEN_ID, token2.getId())
                 .detail(Details.REFRESH_TOKEN_ID, offlineToken2.getId())
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
                 .detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "offline-client")
                 .assertEvent();
 
@@ -371,7 +371,7 @@ public class OfflineTokenTest {
                 .user(serviceAccountUserId)
                 .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID)
                 .removeDetail(Details.TOKEN_ID)
-                .detail(Details.REFRESH_TOKEN_TYPE, RefreshTokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
                 .assertEvent();
 
         // Refresh with new offline token is ok
@@ -389,7 +389,7 @@ public class OfflineTokenTest {
         loginPage.login("test-user@localhost", "password");
         Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
 
-        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
         Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getExpiration(), 0);
 
         String accessTokenId = OfflineTokenServlet.tokenInfo.accessToken.getId();
@@ -422,7 +422,7 @@ public class OfflineTokenTest {
         loginPage.login("test-user@localhost", "password");
         Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
 
-        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
 
         // Assert refresh works with increased time
         Time.setOffset(9999);
@@ -480,7 +480,7 @@ public class OfflineTokenTest {
         oauthGrantPage.accept();
 
         Assert.assertTrue(driver.getCurrentUrl().startsWith(offlineClientAppUri));
-        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), RefreshTokenUtil.TOKEN_TYPE_OFFLINE);
+        Assert.assertEquals(OfflineTokenServlet.tokenInfo.refreshToken.getType(), TokenUtil.TOKEN_TYPE_OFFLINE);
 
         accountAppPage.open();
         AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get("offline-client");