keycloak-uncached

Changes

server-spi-private/src/main/java/org/keycloak/keys/AesKeyProviderFactory.java 34(+0 -34)

server-spi-private/src/main/java/org/keycloak/keys/RsaKeyProvider.java 60(+0 -60)

server-spi-private/src/main/java/org/keycloak/keys/SecretKeyProvider.java 50(+0 -50)

Details

diff --git a/core/src/main/java/org/keycloak/crypto/JavaAlgorithm.java b/core/src/main/java/org/keycloak/crypto/JavaAlgorithm.java
new file mode 100644
index 0000000..46d084c
--- /dev/null
+++ b/core/src/main/java/org/keycloak/crypto/JavaAlgorithm.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.crypto;
+
+public class JavaAlgorithm {
+
+    public static String getJavaAlgorithm(String algorithm) {
+        switch (algorithm) {
+            case Algorithm.RS256:
+                return "SHA256withRSA";
+            case Algorithm.RS384:
+                return "SHA384withRSA";
+            case Algorithm.RS512:
+                return "SHA512withRSA";
+            case Algorithm.HS256:
+                return "HMACSHA256";
+            case Algorithm.HS384:
+                return "HMACSHA384";
+            case Algorithm.HS512:
+                return "HMACSHA512";
+            case Algorithm.AES:
+                return "AES";
+            default:
+                throw new IllegalArgumentException("Unkown algorithm " + algorithm);
+        }
+    }
+
+}
diff --git a/core/src/main/java/org/keycloak/crypto/KeyWrapper.java b/core/src/main/java/org/keycloak/crypto/KeyWrapper.java
new file mode 100644
index 0000000..2a592aa
--- /dev/null
+++ b/core/src/main/java/org/keycloak/crypto/KeyWrapper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.crypto;
+
+import javax.crypto.SecretKey;
+import java.security.Key;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class KeyWrapper {
+
+    private String providerId;
+    private long providerPriority;
+    private String kid;
+    private Set<String> algorithms;
+    private String type;
+    private KeyUse use;
+    private KeyStatus status;
+    private SecretKey secretKey;
+    private Key signKey;
+    private Key verifyKey;
+    private X509Certificate certificate;
+
+    public String getProviderId() {
+        return providerId;
+    }
+
+    public void setProviderId(String providerId) {
+        this.providerId = providerId;
+    }
+
+    public long getProviderPriority() {
+        return providerPriority;
+    }
+
+    public void setProviderPriority(long providerPriority) {
+        this.providerPriority = providerPriority;
+    }
+
+    public String getKid() {
+        return kid;
+    }
+
+    public void setKid(String kid) {
+        this.kid = kid;
+    }
+
+    public Set<String> getAlgorithms() {
+        return algorithms;
+    }
+
+    public void setAlgorithms(String... algorithms) {
+        this.algorithms = new HashSet<>();
+        for (String a : algorithms) {
+            this.algorithms.add(a);
+        }
+    }
+
+    public void setAlgorithms(Set<String> algorithms) {
+        this.algorithms = algorithms;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public KeyUse getUse() {
+        return use;
+    }
+
+    public void setUse(KeyUse use) {
+        this.use = use;
+    }
+
+    public KeyStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(KeyStatus status) {
+        this.status = status;
+    }
+
+    public SecretKey getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(SecretKey secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public Key getSignKey() {
+        return signKey;
+    }
+
+    public void setSignKey(Key signKey) {
+        this.signKey = signKey;
+    }
+
+    public Key getVerifyKey() {
+        return verifyKey;
+    }
+
+    public void setVerifyKey(Key verifyKey) {
+        this.verifyKey = verifyKey;
+    }
+
+    public X509Certificate getCertificate() {
+        return certificate;
+    }
+
+    public void setCertificate(X509Certificate certificate) {
+        this.certificate = certificate;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java
index 54d3ba9..e70c273 100644
--- a/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java
@@ -19,6 +19,7 @@ package org.keycloak.representations.idm;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -54,6 +55,7 @@ public class KeysMetadataRepresentation {
         private String status;
 
         private String type;
+        private Set<String> algorithms;
 
         private String publicKey;
         private String certificate;
@@ -98,6 +100,14 @@ public class KeysMetadataRepresentation {
             this.type = type;
         }
 
+        public Set<String> getAlgorithms() {
+            return algorithms;
+        }
+
+        public void setAlgorithms(Set<String> algorithms) {
+            this.algorithms = algorithms;
+        }
+
         public String getPublicKey() {
             return publicKey;
         }
diff --git a/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java b/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java
index c9adebd..296a413 100644
--- a/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java
+++ b/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java
@@ -17,21 +17,19 @@
 
 package org.keycloak.keys;
 
+import org.keycloak.crypto.KeyStatus;
+
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public abstract class KeyMetadata {
 
-    public enum Status {
-        ACTIVE, PASSIVE, DISABLED
-    }
-
     private String providerId;
     private long providerPriority;
 
     private String kid;
 
-    private Status status;
+    private KeyStatus status;
 
     public String getProviderId() {
         return providerId;
@@ -57,11 +55,11 @@ public abstract class KeyMetadata {
         this.kid = kid;
     }
 
-    public Status getStatus() {
+    public KeyStatus getStatus() {
         return status;
     }
 
-    public void setStatus(Status status) {
+    public void setStatus(KeyStatus status) {
         this.status = status;
     }
 
diff --git a/server-spi/src/main/java/org/keycloak/models/KeyManager.java b/server-spi/src/main/java/org/keycloak/models/KeyManager.java
index bc47dcb..f7a9b40 100644
--- a/server-spi/src/main/java/org/keycloak/models/KeyManager.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeyManager.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.models;
 
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.keys.SecretKeyMetadata;
 import org.keycloak.keys.RsaKeyMetadata;
 
@@ -32,25 +34,43 @@ import java.util.List;
  */
 public interface KeyManager {
 
+    KeyWrapper getActiveKey(RealmModel realm, KeyUse use, String algorithm);
+
+    KeyWrapper getKey(RealmModel realm, String kid, KeyUse use, String algorithm);
+
+    List<KeyWrapper> getKeys(RealmModel realm);
+
+    List<KeyWrapper> getKeys(RealmModel realm, KeyUse use, String algorithm);
+
+    @Deprecated
     ActiveRsaKey getActiveRsaKey(RealmModel realm);
 
+    @Deprecated
     PublicKey getRsaPublicKey(RealmModel realm, String kid);
 
+    @Deprecated
     Certificate getRsaCertificate(RealmModel realm, String kid);
 
-    List<RsaKeyMetadata> getRsaKeys(RealmModel realm, boolean includeDisabled);
+    @Deprecated
+    List<RsaKeyMetadata> getRsaKeys(RealmModel realm);
 
+    @Deprecated
     ActiveHmacKey getActiveHmacKey(RealmModel realm);
 
+    @Deprecated
     SecretKey getHmacSecretKey(RealmModel realm, String kid);
 
-    List<SecretKeyMetadata> getHmacKeys(RealmModel realm, boolean includeDisabled);
+    @Deprecated
+    List<SecretKeyMetadata> getHmacKeys(RealmModel realm);
 
+    @Deprecated
     ActiveAesKey getActiveAesKey(RealmModel realm);
 
+    @Deprecated
     SecretKey getAesSecretKey(RealmModel realm, String kid);
 
-    List<SecretKeyMetadata> getAesKeys(RealmModel realm, boolean includeDisabled);
+    @Deprecated
+    List<SecretKeyMetadata> getAesKeys(RealmModel realm);
 
     class ActiveRsaKey {
         private final String kid;
diff --git a/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java b/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java
index fb9e152..7984ea6 100644
--- a/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.keys;
 
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.jose.jws.AlgorithmType;
 import org.keycloak.provider.Provider;
 
@@ -28,26 +29,15 @@ import java.util.List;
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public interface KeyProvider<T extends KeyMetadata> extends Provider {
+public interface KeyProvider extends Provider {
 
     /**
-     * Returns the algorithm type the keys can be used for
-     *
+     * Returns the key
      * @return
      */
-    AlgorithmType getType();
+    List<KeyWrapper> getKeys();
 
-    /**
-     * Return the KID for the active keypair, or <code>null</code> if no active key is available.
-     *
-     * @return
-     */
-    String getKid();
-
-    /**
-     * Return metadata about all keypairs held by the provider
-     * @return
-     */
-    List<T> getKeyMetadata();
+    default void close() {
+    }
 
 }
diff --git a/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java
index be005b8..3c8766c 100644
--- a/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java
@@ -17,9 +17,11 @@
 
 package org.keycloak.keys;
 
+import org.keycloak.Config;
 import org.keycloak.component.ComponentFactory;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -28,4 +30,16 @@ public interface KeyProviderFactory<T extends KeyProvider> extends ComponentFact
 
     T create(KeycloakSession session, ComponentModel model);
 
+    @Override
+    default void init(Config.Scope config) {
+    }
+
+    @Override
+    default void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    default void close() {
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 83a3756..5a9a4c7 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -17,33 +17,25 @@
 package org.keycloak.broker.saml;
 
 import org.jboss.logging.Logger;
-import org.keycloak.broker.provider.AbstractIdentityProvider;
-import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.BrokeredIdentityContext;
-import org.keycloak.broker.provider.IdentityBrokerException;
-import org.keycloak.broker.provider.IdentityProviderDataMarshaller;
+import org.keycloak.broker.provider.*;
 import org.keycloak.broker.provider.util.SimpleHttp;
 import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.KeyStatus;
 import org.keycloak.dom.saml.v2.assertion.AssertionType;
 import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
 import org.keycloak.dom.saml.v2.assertion.NameIDType;
 import org.keycloak.dom.saml.v2.assertion.SubjectType;
+import org.keycloak.dom.saml.v2.metadata.KeyTypes;
 import org.keycloak.dom.saml.v2.protocol.ResponseType;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.keys.RsaKeyMetadata;
-import org.keycloak.models.FederatedIdentityModel;
-import org.keycloak.models.KeyManager;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.*;
 import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
-import org.keycloak.saml.SAML2AuthnRequestBuilder;
-import org.keycloak.saml.SAML2LogoutRequestBuilder;
-import org.keycloak.saml.SAML2NameIDPolicyBuilder;
-import org.keycloak.saml.SPMetadataDescriptor;
-import org.keycloak.saml.SignatureAlgorithm;
+import org.keycloak.saml.*;
 import org.keycloak.saml.common.constants.GeneralConstants;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
+import org.keycloak.sessions.AuthenticationSessionModel;
 
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -52,11 +44,6 @@ import javax.ws.rs.core.UriInfo;
 import java.security.KeyPair;
 import java.util.Set;
 import java.util.TreeSet;
-import org.keycloak.dom.saml.v2.metadata.KeyTypes;
-import org.keycloak.keys.KeyMetadata;
-import org.keycloak.keys.KeyMetadata.Status;
-import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
-import org.keycloak.sessions.AuthenticationSessionModel;
 
 /**
  * @author Pedro Igor
@@ -246,12 +233,12 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
         StringBuilder encryptionKeysString = new StringBuilder();
         Set<RsaKeyMetadata> keys = new TreeSet<>((o1, o2) -> o1.getStatus() == o2.getStatus() // Status can be only PASSIVE OR ACTIVE, push PASSIVE to end of list
           ? (int) (o2.getProviderPriority() - o1.getProviderPriority())
-          : (o1.getStatus() == KeyMetadata.Status.PASSIVE ? 1 : -1));
-        keys.addAll(session.keys().getRsaKeys(realm, false));
+          : (o1.getStatus() == KeyStatus.PASSIVE ? 1 : -1));
+        keys.addAll(session.keys().getRsaKeys(realm));
         for (RsaKeyMetadata key : keys) {
             addKeyInfo(signingKeysString, key, KeyTypes.SIGNING.value());
 
-            if (key.getStatus() == Status.ACTIVE) {
+            if (key.getStatus() == KeyStatus.ACTIVE) {
                 addKeyInfo(encryptionKeysString, key, KeyTypes.ENCRYPTION.value());
             }
         }
diff --git a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
index 0584a75..8a715b8 100644
--- a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
@@ -17,13 +17,12 @@
 
 package org.keycloak.keys;
 
+import org.keycloak.common.util.KeyUtils;
 import org.keycloak.component.ComponentModel;
-import org.keycloak.jose.jws.AlgorithmType;
+import org.keycloak.crypto.*;
 import org.keycloak.models.RealmModel;
 
 import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
 import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.List;
@@ -31,110 +30,49 @@ import java.util.List;
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public abstract class AbstractRsaKeyProvider implements RsaKeyProvider {
+public abstract class AbstractRsaKeyProvider implements KeyProvider {
 
-    private final boolean enabled;
-
-    private final boolean active;
+    private final KeyStatus status;
 
     private final ComponentModel model;
 
-    private final Keys keys;
+    private final KeyWrapper key;
 
     public AbstractRsaKeyProvider(RealmModel realm, ComponentModel model) {
         this.model = model;
+        this.status = KeyStatus.from(model.get(Attributes.ACTIVE_KEY, true), model.get(Attributes.ENABLED_KEY, true));
 
-        this.enabled = model.get(Attributes.ENABLED_KEY, true);
-        this.active = model.get(Attributes.ACTIVE_KEY, true);
-
-        if (model.hasNote(Keys.class.getName())) {
-            keys = model.getNote(Keys.class.getName());
+        if (model.hasNote(KeyWrapper.class.getName())) {
+            key = model.getNote(KeyWrapper.class.getName());
         } else {
-            keys = loadKeys(realm, model);
-            model.setNote(Keys.class.getName(), keys);
+            key = loadKey(realm, model);
+            model.setNote(KeyWrapper.class.getName(), key);
         }
     }
 
-    protected abstract Keys loadKeys(RealmModel realm, ComponentModel model);
-
-    @Override
-    public final String getKid() {
-        return isActive() ? keys.getKid() : null;
-    }
-
-    @Override
-    public final PrivateKey getPrivateKey() {
-        return isActive() ? keys.getKeyPair().getPrivate() : null;
-    }
-
-    @Override
-    public final PublicKey getPublicKey(String kid) {
-        return isEnabled() && kid.equals(keys.getKid()) ? keys.getKeyPair().getPublic() : null;
-    }
-
-    @Override
-    public X509Certificate getCertificate(String kid) {
-        return isEnabled() && kid.equals(keys.getKid()) ? keys.getCertificate() : null;
-    }
-
-    @Override
-    public final List<RsaKeyMetadata> getKeyMetadata() {
-        String kid = keys.getKid();
-        PublicKey publicKey = keys.getKeyPair().getPublic();
-        if (kid != null && publicKey != null) {
-            RsaKeyMetadata k = new RsaKeyMetadata();
-            k.setProviderId(model.getId());
-            k.setProviderPriority(model.get(Attributes.PRIORITY_KEY, 0l));
-            k.setKid(kid);
-            if (isActive()) {
-                k.setStatus(KeyMetadata.Status.ACTIVE);
-            } else if (isEnabled()) {
-                k.setStatus(KeyMetadata.Status.PASSIVE);
-            } else {
-                k.setStatus(KeyMetadata.Status.DISABLED);
-            }
-            k.setPublicKey(publicKey);
-            k.setCertificate(keys.getCertificate());
-            return Collections.singletonList(k);
-        } else {
-            return Collections.emptyList();
-        }
-    }
+    protected abstract KeyWrapper loadKey(RealmModel realm, ComponentModel model);
 
     @Override
-    public void close() {
-    }
-
-    private boolean isEnabled() {
-        return keys != null && enabled;
+    public List<KeyWrapper> getKeys() {
+        return Collections.singletonList(key);
     }
 
-    private boolean isActive() {
-        return isEnabled() && active;
-    }
-
-    public static class Keys {
-        private String kid;
-        private KeyPair keyPair;
-        private X509Certificate certificate;
+    protected KeyWrapper createKeyWrapper(KeyPair keyPair, X509Certificate certificate) {
+        KeyWrapper key = new KeyWrapper();
 
-        public Keys(String kid, KeyPair keyPair, X509Certificate certificate) {
-            this.kid = kid;
-            this.keyPair = keyPair;
-            this.certificate = certificate;
-        }
+        key.setProviderId(model.getId());
+        key.setProviderPriority(model.get("priority", 0l));
 
-        public String getKid() {
-            return kid;
-        }
+        key.setKid(KeyUtils.createKeyId(keyPair.getPublic()));
+        key.setUse(KeyUse.SIG);
+        key.setType(KeyType.RSA);
+        key.setAlgorithms(Algorithm.RS256, Algorithm.RS384, Algorithm.RS512);
+        key.setStatus(status);
+        key.setSignKey(keyPair.getPrivate());
+        key.setVerifyKey(keyPair.getPublic());
+        key.setCertificate(certificate);
 
-        public KeyPair getKeyPair() {
-            return keyPair;
-        }
-
-        public X509Certificate getCertificate() {
-            return certificate;
-        }
+        return key;
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java
index f20dc20..1c2af4f 100644
--- a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java
@@ -27,7 +27,7 @@ import org.keycloak.provider.ProviderConfigurationBuilder;
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public abstract class AbstractRsaKeyProviderFactory implements RsaKeyProviderFactory {
+public abstract class AbstractRsaKeyProviderFactory implements KeyProviderFactory {
 
     public final static ProviderConfigurationBuilder configurationBuilder() {
         return ProviderConfigurationBuilder.create()
diff --git a/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java b/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java
index 6a33293..7ebb1a4 100644
--- a/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java
+++ b/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java
@@ -19,20 +19,19 @@ package org.keycloak.keys;
 
 import org.jboss.logging.Logger;
 import org.keycloak.component.ComponentModel;
-import org.keycloak.jose.jws.AlgorithmType;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.models.KeyManager;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.provider.ProviderFactory;
 
 import javax.crypto.SecretKey;
+import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.cert.Certificate;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -49,204 +48,172 @@ public class DefaultKeyManager implements KeyManager {
     }
 
     @Override
-    public ActiveRsaKey getActiveRsaKey(RealmModel realm) {
+    public KeyWrapper getActiveKey(RealmModel realm, KeyUse use, String algorithm) {
         for (KeyProvider p : getProviders(realm)) {
-            if (p.getType().equals(AlgorithmType.RSA)) {
-                RsaKeyProvider r = (RsaKeyProvider) p;
-                if (r.getKid() != null && r.getPrivateKey() != null) {
+            for (KeyWrapper key : p .getKeys()) {
+                if (key.getStatus().isActive() && matches(key, use, algorithm)) {
                     if (logger.isTraceEnabled()) {
-                        logger.tracev("Active key realm={0} kid={1}", realm.getName(), p.getKid());
+                        logger.tracev("Active key found: realm={0} kid={1} algorithm={2}", realm.getName(), key.getKid(), algorithm);
                     }
-                    String kid = p.getKid();
-                    return new ActiveRsaKey(kid, r.getPrivateKey(), r.getPublicKey(kid), r.getCertificate(kid));
-                }
-            }
-        }
-        throw new RuntimeException("Failed to get RSA keys");
-    }
-
-    @Override
-    public ActiveHmacKey getActiveHmacKey(RealmModel realm) {
-        for (KeyProvider p : getProviders(realm)) {
-            if (p.getType().equals(AlgorithmType.HMAC)) {
-                HmacKeyProvider h = (HmacKeyProvider) p;
-                if (h.getKid() != null && h.getSecretKey() != null) {
-                    if (logger.isTraceEnabled()) {
-                        logger.tracev("Active secret realm={0} kid={1}", realm.getName(), p.getKid());
-                    }
-                    String kid = p.getKid();
-                    return new ActiveHmacKey(kid, h.getSecretKey());
-                }
-            }
-        }
-        throw new RuntimeException("Failed to get keys");
-    }
 
-    @Override
-    public ActiveAesKey getActiveAesKey(RealmModel realm) {
-        for (KeyProvider p : getProviders(realm)) {
-            if (p.getType().equals(AlgorithmType.AES)) {
-                AesKeyProvider h = (AesKeyProvider) p;
-                if (h.getKid() != null && h.getSecretKey() != null) {
-                    if (logger.isTraceEnabled()) {
-                        logger.tracev("Active AES Key realm={0} kid={1}", realm.getName(), p.getKid());
-                    }
-                    String kid = p.getKid();
-                    return new ActiveAesKey(kid, h.getSecretKey());
+                    return key;
                 }
             }
         }
-        throw new RuntimeException("Failed to get keys");
+        throw new RuntimeException("Failed to find key: realm=" + realm.getName() + " algorithm=" + algorithm);
     }
 
     @Override
-    public PublicKey getRsaPublicKey(RealmModel realm, String kid) {
+    public KeyWrapper getKey(RealmModel realm, String kid, KeyUse use, String algorithm) {
         if (kid == null) {
-            logger.warnv("KID is null, can't find public key", realm.getName(), kid);
+            logger.warnv("kid is null, can't find public key", realm.getName(), kid);
             return null;
         }
 
         for (KeyProvider p : getProviders(realm)) {
-            if (p.getType().equals(AlgorithmType.RSA)) {
-                RsaKeyProvider r = (RsaKeyProvider) p;
-                PublicKey publicKey = r.getPublicKey(kid);
-                if (publicKey != null) {
+            for (KeyWrapper key : p.getKeys()) {
+                if (key.getKid().equals(kid) && key.getStatus().isEnabled() && matches(key, use, algorithm)) {
                     if (logger.isTraceEnabled()) {
-                        logger.tracev("Found public key realm={0} kid={1}", realm.getName(), kid);
+                        logger.tracev("Active key realm={0} kid={1} algorithm={2}", realm.getName(), key.getKid(), algorithm);
                     }
-                    return publicKey;
+
+                    return key;
                 }
             }
         }
+
         if (logger.isTraceEnabled()) {
-            logger.tracev("Failed to find public key realm={0} kid={1}", realm.getName(), kid);
+            logger.tracev("Failed to find public key realm={0} kid={1} algorithm={2}", realm.getName(), kid, algorithm);
         }
+
         return null;
     }
 
     @Override
-    public Certificate getRsaCertificate(RealmModel realm, String kid) {
-        if (kid == null) {
-            logger.warnv("KID is null, can't find public key", realm.getName(), kid);
-            return null;
-        }
-
+    public List<KeyWrapper> getKeys(RealmModel realm, KeyUse use, String algorithm) {
+        List<KeyWrapper> keys = new LinkedList<>();
         for (KeyProvider p : getProviders(realm)) {
-            if (p.getType().equals(AlgorithmType.RSA)) {
-                RsaKeyProvider r = (RsaKeyProvider) p;
-                Certificate certificate = r.getCertificate(kid);
-                if (certificate != null) {
-                    if (logger.isTraceEnabled()) {
-                        logger.tracev("Found certificate realm={0} kid={1}", realm.getName(), kid);
-                    }
-                    return certificate;
+            for (KeyWrapper key : p .getKeys()) {
+                if (key.getStatus().isEnabled() && matches(key, use, algorithm)) {
+                    keys.add(key);
                 }
             }
         }
-        if (logger.isTraceEnabled()) {
-            logger.tracev("Failed to find certificate realm={0} kid={1}", realm.getName(), kid);
-        }
-        return null;
+        return keys;
     }
 
     @Override
-    public SecretKey getHmacSecretKey(RealmModel realm, String kid) {
-        if (kid == null) {
-            logger.warnv("KID is null, can't find secret key", realm.getName(), kid);
-            return null;
-        }
-
+    public List<KeyWrapper> getKeys(RealmModel realm) {
+        List<KeyWrapper> keys = new LinkedList<>();
         for (KeyProvider p : getProviders(realm)) {
-            if (p.getType().equals(AlgorithmType.HMAC)) {
-                HmacKeyProvider h = (HmacKeyProvider) p;
-                SecretKey s = h.getSecretKey(kid);
-                if (s != null) {
-                    if (logger.isTraceEnabled()) {
-                        logger.tracev("Found secret key realm={0} kid={1}", realm.getName(), kid);
-                    }
-                    return s;
-                }
+            for (KeyWrapper key : p .getKeys()) {
+                keys.add(key);
             }
         }
-        if (logger.isTraceEnabled()) {
-            logger.tracev("Failed to find secret key realm={0} kid={1}", realm.getName(), kid);
-        }
-        return null;
+        return keys;
     }
 
     @Override
-    public SecretKey getAesSecretKey(RealmModel realm, String kid) {
-        if (kid == null) {
-            logger.warnv("KID is null, can't find aes key", realm.getName(), kid);
-            return null;
-        }
+    @Deprecated
+    public ActiveRsaKey getActiveRsaKey(RealmModel realm) {
+        KeyWrapper key = getActiveKey(realm, KeyUse.SIG, Algorithm.RS256);
+        return new ActiveRsaKey(key.getKid(), (PrivateKey) key.getSignKey(), (PublicKey) key.getVerifyKey(), key.getCertificate());
+    }
 
-        for (KeyProvider p : getProviders(realm)) {
-            if (p.getType().equals(AlgorithmType.AES)) {
-                AesKeyProvider h = (AesKeyProvider) p;
-                SecretKey s = h.getSecretKey(kid);
-                if (s != null) {
-                    if (logger.isTraceEnabled()) {
-                        logger.tracev("Found AES key realm={0} kid={1}", realm.getName(), kid);
-                    }
-                    return s;
-                }
-            }
-        }
-        if (logger.isTraceEnabled()) {
-            logger.tracev("Failed to find AES key realm={0} kid={1}", realm.getName(), kid);
-        }
-        return null;
+    @Override
+    @Deprecated
+    public ActiveHmacKey getActiveHmacKey(RealmModel realm) {
+        KeyWrapper key = getActiveKey(realm, KeyUse.SIG, Algorithm.HS256);
+        return new ActiveHmacKey(key.getKid(), key.getSecretKey());
     }
 
     @Override
-    public List<RsaKeyMetadata> getRsaKeys(RealmModel realm, boolean includeDisabled) {
+    @Deprecated
+    public ActiveAesKey getActiveAesKey(RealmModel realm) {
+        KeyWrapper key = getActiveKey(realm, KeyUse.ENC, Algorithm.AES);
+        return new ActiveAesKey(key.getKid(), key.getSecretKey());
+    }
+
+    @Override
+    @Deprecated
+    public PublicKey getRsaPublicKey(RealmModel realm, String kid) {
+        KeyWrapper key = getKey(realm, kid, KeyUse.SIG, Algorithm.RS256);
+        return key != null ? (PublicKey) key.getVerifyKey() : null;
+    }
+
+    @Override
+    @Deprecated
+    public Certificate getRsaCertificate(RealmModel realm, String kid) {
+        KeyWrapper key = getKey(realm, kid, KeyUse.SIG, Algorithm.RS256);
+        return key != null ? key.getCertificate() : null;
+    }
+
+    @Override
+    @Deprecated
+    public SecretKey getHmacSecretKey(RealmModel realm, String kid) {
+        KeyWrapper key = getKey(realm, kid, KeyUse.SIG, Algorithm.HS256);
+        return key != null ? key.getSecretKey() : null;
+    }
+
+    @Override
+    @Deprecated
+    public SecretKey getAesSecretKey(RealmModel realm, String kid) {
+        KeyWrapper key = getKey(realm, kid, KeyUse.ENC, Algorithm.AES);
+        return key.getSecretKey();
+    }
+
+    @Override
+    @Deprecated
+    public List<RsaKeyMetadata> getRsaKeys(RealmModel realm) {
         List<RsaKeyMetadata> keys = new LinkedList<>();
-        for (KeyProvider p : getProviders(realm)) {
-            if (p instanceof RsaKeyProvider) {
-                if (includeDisabled) {
-                    keys.addAll(p.getKeyMetadata());
-                } else {
-                    List<RsaKeyMetadata> metadata = p.getKeyMetadata();
-                    metadata.stream().filter(k -> k.getStatus() != KeyMetadata.Status.DISABLED).forEach(k -> keys.add(k));
-                }
-            }
+        for (KeyWrapper key : getKeys(realm, KeyUse.SIG, Algorithm.RS256)) {
+            RsaKeyMetadata m = new RsaKeyMetadata();
+            m.setCertificate(key.getCertificate());
+            m.setPublicKey((PublicKey) key.getVerifyKey());
+            m.setKid(key.getKid());
+            m.setProviderId(key.getProviderId());
+            m.setProviderPriority(key.getProviderPriority());
+            m.setStatus(key.getStatus());
+
+            keys.add(m);
         }
         return keys;
     }
 
     @Override
-    public List<SecretKeyMetadata> getHmacKeys(RealmModel realm, boolean includeDisabled) {
+    public List<SecretKeyMetadata> getHmacKeys(RealmModel realm) {
         List<SecretKeyMetadata> keys = new LinkedList<>();
-        for (KeyProvider p : getProviders(realm)) {
-            if (p instanceof HmacKeyProvider) {
-                if (includeDisabled) {
-                    keys.addAll(p.getKeyMetadata());
-                } else {
-                    List<SecretKeyMetadata> metadata = p.getKeyMetadata();
-                    metadata.stream().filter(k -> k.getStatus() != KeyMetadata.Status.DISABLED).forEach(k -> keys.add(k));
-                }
-            }
+        for (KeyWrapper key : getKeys(realm, KeyUse.SIG, Algorithm.HS256)) {
+            SecretKeyMetadata m = new SecretKeyMetadata();
+            m.setKid(key.getKid());
+            m.setProviderId(key.getProviderId());
+            m.setProviderPriority(key.getProviderPriority());
+            m.setStatus(key.getStatus());
+
+            keys.add(m);
         }
         return keys;
     }
 
     @Override
-    public List<SecretKeyMetadata> getAesKeys(RealmModel realm, boolean includeDisabled) {
+    public List<SecretKeyMetadata> getAesKeys(RealmModel realm) {
         List<SecretKeyMetadata> keys = new LinkedList<>();
-        for (KeyProvider p : getProviders(realm)) {
-            if (p instanceof AesKeyProvider) {
-                if (includeDisabled) {
-                    keys.addAll(p.getKeyMetadata());
-                } else {
-                    List<SecretKeyMetadata> metadata = p.getKeyMetadata();
-                    metadata.stream().filter(k -> k.getStatus() != KeyMetadata.Status.DISABLED).forEach(k -> keys.add(k));
-                }
-            }
+        for (KeyWrapper key : getKeys(realm, KeyUse.ENC, Algorithm.AES)) {
+            SecretKeyMetadata m = new SecretKeyMetadata();
+            m.setKid(key.getKid());
+            m.setProviderId(key.getProviderId());
+            m.setProviderPriority(key.getProviderPriority());
+            m.setStatus(key.getStatus());
+
+            keys.add(m);
         }
         return keys;
     }
 
+    private boolean matches(KeyWrapper key, KeyUse use, String algorithm) {
+        return use.equals(key.getUse()) && key.getAlgorithms().contains(algorithm);
+    }
+
     private List<KeyProvider> getProviders(RealmModel realm) {
         List<KeyProvider> providers = providersMap.get(realm.getId());
         if (providers == null) {
@@ -255,10 +222,6 @@ public class DefaultKeyManager implements KeyManager {
             List<ComponentModel> components = new LinkedList<>(realm.getComponents(realm.getId(), KeyProvider.class.getName()));
             components.sort(new ProviderComparator());
 
-            boolean activeRsa = false;
-            boolean activeHmac = false;
-            boolean activeAes = false;
-
             for (ComponentModel c : components) {
                 try {
                     ProviderFactory<KeyProvider> f = session.getKeycloakSessionFactory().getProviderFactory(KeyProvider.class, c.getProviderId());
@@ -266,41 +229,30 @@ public class DefaultKeyManager implements KeyManager {
                     KeyProvider provider = factory.create(session, c);
                     session.enlistForClose(provider);
                     providers.add(provider);
-                    if (provider.getType().equals(AlgorithmType.RSA)) {
-                        RsaKeyProvider r = (RsaKeyProvider) provider;
-                        if (r.getKid() != null && r.getPrivateKey() != null) {
-                            activeRsa = true;
-                        }
-                    } else if (provider.getType().equals(AlgorithmType.HMAC)) {
-                        HmacKeyProvider r = (HmacKeyProvider) provider;
-                        if (r.getKid() != null && r.getSecretKey() != null) {
-                            activeHmac = true;
-                        }
-                    } else if (provider.getType().equals(AlgorithmType.AES)) {
-                        AesKeyProvider r = (AesKeyProvider) provider;
-                        if (r.getKid() != null && r.getSecretKey() != null) {
-                            activeAes = true;
-                        }
-                    }
-
                 } catch (Throwable t) {
                     logger.errorv(t, "Failed to load provider {0}", c.getId());
                 }
             }
 
-            if (!activeRsa) {
+            providersMap.put(realm.getId(), providers);
+
+            try {
+                getActiveKey(realm, KeyUse.SIG, Algorithm.RS256);
+            } catch (RuntimeException e) {
                 providers.add(new FailsafeRsaKeyProvider());
             }
 
-            if (!activeHmac) {
+            try {
+                getActiveKey(realm, KeyUse.SIG, Algorithm.HS256);
+            } catch (RuntimeException e) {
                 providers.add(new FailsafeHmacKeyProvider());
             }
 
-            if (!activeAes) {
+            try {
+                getActiveKey(realm, KeyUse.ENC, Algorithm.AES);
+            } catch (RuntimeException e) {
                 providers.add(new FailsafeAesKeyProvider());
             }
-
-            providersMap.put(realm.getId(), providers);
         }
         return providers;
     }
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java
index d81a596..bac9f76 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java
@@ -18,15 +18,33 @@
 package org.keycloak.keys;
 
 import org.jboss.logging.Logger;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class FailsafeAesKeyProvider extends FailsafeSecretKeyProvider implements AesKeyProvider {
+public class FailsafeAesKeyProvider extends FailsafeSecretKeyProvider {
 
     private static final Logger logger = Logger.getLogger(FailsafeAesKeyProvider.class);
 
     @Override
+    protected KeyUse getUse() {
+        return KeyUse.ENC;
+    }
+
+    @Override
+    protected String getType() {
+        return KeyType.OCT;
+    }
+
+    @Override
+    protected String getAlgorithm() {
+        return Algorithm.AES;
+    }
+
+    @Override
     protected Logger logger() {
         return logger;
     }
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java
index 676e048..1114c24 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java
@@ -20,6 +20,10 @@ package org.keycloak.keys;
 import org.jboss.logging.Logger;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.Time;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.crypto.SecretKey;
@@ -29,12 +33,28 @@ import java.util.List;
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public class FailsafeHmacKeyProvider extends FailsafeSecretKeyProvider implements HmacKeyProvider {
+public class FailsafeHmacKeyProvider extends FailsafeSecretKeyProvider {
 
     private static final Logger logger = Logger.getLogger(FailsafeHmacKeyProvider.class);
 
     @Override
+    protected KeyUse getUse() {
+        return KeyUse.SIG;
+    }
+
+    @Override
+    protected String getType() {
+        return KeyType.OCT;
+    }
+
+    @Override
+    protected String getAlgorithm() {
+        return Algorithm.HS256;
+    }
+
+    @Override
     protected Logger logger() {
         return logger;
     }
+
 }
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java
index 8515f29..9af84a5 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java
@@ -20,77 +20,62 @@ package org.keycloak.keys;
 import org.jboss.logging.Logger;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.Time;
+import org.keycloak.crypto.*;
 
 import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.List;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public class FailsafeRsaKeyProvider implements RsaKeyProvider {
+public class FailsafeRsaKeyProvider implements KeyProvider {
 
     private static final Logger logger = Logger.getLogger(FailsafeRsaKeyProvider.class);
 
-    private static String KID;
-
-    private static KeyPair KEY_PAIR;
+    private static KeyWrapper KEY;
 
     private static long EXPIRES;
 
-    private KeyPair keyPair;
-
-    private String kid;
+    private KeyWrapper key;
 
     public FailsafeRsaKeyProvider() {
         logger.errorv("No active keys found, using failsafe provider, please login to admin console to add keys. Clustering is not supported.");
 
         synchronized (FailsafeRsaKeyProvider.class) {
             if (EXPIRES < Time.currentTime()) {
-                KEY_PAIR = KeyUtils.generateRsaKeyPair(2048);
-                KID = KeyUtils.createKeyId(KEY_PAIR.getPublic());
+                KEY = createKeyWrapper();
                 EXPIRES = Time.currentTime() + 60 * 10;
 
                 if (EXPIRES > 0) {
-                    logger.warnv("Keys expired, re-generated kid={0}", KID);
+                    logger.warnv("Keys expired, re-generated kid={0}", KEY.getKid());
                 }
             }
 
-            kid = KID;
-            keyPair = KEY_PAIR;
+            key = KEY;
         }
     }
 
     @Override
-    public String getKid() {
-        return kid;
+    public List<KeyWrapper> getKeys() {
+        return Collections.singletonList(key);
     }
 
-    @Override
-    public PrivateKey getPrivateKey() {
-        return keyPair.getPrivate();
-    }
+    private KeyWrapper createKeyWrapper() {
+        KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
 
-    @Override
-    public PublicKey getPublicKey(String kid) {
-        return kid.equals(this.kid) ? keyPair.getPublic() : null;
-    }
+        KeyWrapper key = new KeyWrapper();
 
-    @Override
-    public X509Certificate getCertificate(String kid) {
-        return null;
-    }
+        key.setKid(KeyUtils.createKeyId(keyPair.getPublic()));
+        key.setUse(KeyUse.SIG);
+        key.setType(KeyType.RSA);
+        key.setAlgorithms(Algorithm.RS256, Algorithm.RS384, Algorithm.RS512);
+        key.setStatus(KeyStatus.ACTIVE);
+        key.setSignKey(keyPair.getPrivate());
+        key.setVerifyKey(keyPair.getPublic());
 
-    @Override
-    public List<RsaKeyMetadata> getKeyMetadata() {
-        return Collections.emptyList();
+        return key;
     }
 
-    @Override
-    public void close() {
-    }
 
 }
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java
index 32be263..2cb565d 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java
@@ -17,74 +17,72 @@
 
 package org.keycloak.keys;
 
-import java.util.Collections;
-import java.util.List;
-
-import javax.crypto.SecretKey;
-
 import org.jboss.logging.Logger;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.Time;
+import org.keycloak.crypto.JavaAlgorithm;
+import org.keycloak.crypto.KeyStatus;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
+import javax.crypto.SecretKey;
+import java.util.Collections;
+import java.util.List;
+
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public abstract class FailsafeSecretKeyProvider implements SecretKeyProvider {
-
-
-    private static String KID;
+public abstract class FailsafeSecretKeyProvider implements KeyProvider {
 
-    private static SecretKey KEY;
+    private static KeyWrapper KEY;
 
     private static long EXPIRES;
 
-    private SecretKey key;
-
-    private String kid;
+    private KeyWrapper key;
 
     public FailsafeSecretKeyProvider() {
         logger().errorv("No active keys found, using failsafe provider, please login to admin console to add keys. Clustering is not supported.");
 
         synchronized (FailsafeHmacKeyProvider.class) {
             if (EXPIRES < Time.currentTime()) {
-                KEY = KeyUtils.loadSecretKey(KeycloakModelUtils.generateSecret(32), getJavaAlgorithmName());
-                KID = KeycloakModelUtils.generateId();
+                KEY = createKeyWrapper();
                 EXPIRES = Time.currentTime() + 60 * 10;
 
                 if (EXPIRES > 0) {
-                    logger().warnv("Keys expired, re-generated kid={0}", KID);
+                    logger().warnv("Keys expired, re-generated kid={0}", KEY.getKid());
                 }
             }
 
-            kid = KID;
             key = KEY;
         }
     }
 
     @Override
-    public String getKid() {
-        return kid;
+    public List<KeyWrapper> getKeys() {
+        return Collections.singletonList(key);
     }
 
-    @Override
-    public SecretKey getSecretKey() {
+    private KeyWrapper createKeyWrapper() {
+        SecretKey secretKey = KeyUtils.loadSecretKey(KeycloakModelUtils.generateSecret(32), JavaAlgorithm.getJavaAlgorithm(getAlgorithm()));
+
+        KeyWrapper key = new KeyWrapper();
+
+        key.setKid(KeycloakModelUtils.generateId());
+        key.setUse(getUse());
+        key.setType(getType());
+        key.setAlgorithms(getAlgorithm());
+        key.setStatus(KeyStatus.ACTIVE);
+        key.setSecretKey(secretKey);
+
         return key;
     }
 
-    @Override
-    public SecretKey getSecretKey(String kid) {
-        return kid.equals(this.kid) ? key : null;
-    }
+    protected abstract KeyUse getUse();
 
-    @Override
-    public List<SecretKeyMetadata> getKeyMetadata() {
-        return Collections.emptyList();
-    }
+    protected abstract String getType();
 
-    @Override
-    public void close() {
-    }
+    protected abstract String getAlgorithm();
 
     protected abstract Logger logger();
 }
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java
index cb07323..5a25f31 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java
@@ -18,14 +18,17 @@
 package org.keycloak.keys;
 
 import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class GeneratedAesKeyProvider extends GeneratedSecretKeyProvider implements AesKeyProvider {
+public class GeneratedAesKeyProvider extends GeneratedSecretKeyProvider implements KeyProvider {
 
     public GeneratedAesKeyProvider(ComponentModel model) {
-        super(model);
+        super(model, KeyUse.ENC, KeyType.OCT, Algorithm.AES);
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java
index b9f5a06..e8974aa 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.jboss.logging.Logger;
 import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.KeyUse;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.provider.ProviderConfigProperty;
 
@@ -29,7 +30,7 @@ import static org.keycloak.provider.ProviderConfigProperty.LIST_TYPE;
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class GeneratedAesKeyProviderFactory extends GeneratedSecretKeyProviderFactory<AesKeyProvider> implements AesKeyProviderFactory {
+public class GeneratedAesKeyProviderFactory extends GeneratedSecretKeyProviderFactory<GeneratedSecretKeyProvider> {
 
     private static final Logger logger = Logger.getLogger(GeneratedAesKeyProviderFactory.class);
 
@@ -52,7 +53,7 @@ public class GeneratedAesKeyProviderFactory extends GeneratedSecretKeyProviderFa
             .build();
 
     @Override
-    public AesKeyProvider create(KeycloakSession session, ComponentModel model) {
+    public GeneratedAesKeyProvider create(KeycloakSession session, ComponentModel model) {
         return new GeneratedAesKeyProvider(model);
     }
 
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java
index dfc8fb2..2367a16 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java
@@ -18,15 +18,18 @@
 package org.keycloak.keys;
 
 import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
 
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public class GeneratedHmacKeyProvider extends GeneratedSecretKeyProvider implements HmacKeyProvider {
+public class GeneratedHmacKeyProvider extends GeneratedSecretKeyProvider {
 
     public GeneratedHmacKeyProvider(ComponentModel model) {
-        super(model);
+        super(model, KeyUse.SIG, KeyType.OCT, Algorithm.HS256);
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java
index ab4902a..9f58876 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java
@@ -34,7 +34,7 @@ import java.util.List;
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public class GeneratedHmacKeyProviderFactory extends GeneratedSecretKeyProviderFactory<HmacKeyProvider> implements HmacKeyProviderFactory {
+public class GeneratedHmacKeyProviderFactory extends GeneratedSecretKeyProviderFactory<GeneratedHmacKeyProvider> {
 
     private static final Logger logger = Logger.getLogger(GeneratedHmacKeyProviderFactory.class);
 
@@ -49,7 +49,7 @@ public class GeneratedHmacKeyProviderFactory extends GeneratedSecretKeyProviderF
             .build();
 
     @Override
-    public HmacKeyProvider create(KeycloakSession session, ComponentModel model) {
+    public GeneratedHmacKeyProvider create(KeycloakSession session, ComponentModel model) {
         return new GeneratedHmacKeyProvider(model);
     }
 
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java
index a0a5e87..4aa10da 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java
@@ -111,18 +111,6 @@ public class GeneratedRsaKeyProviderFactory extends AbstractRsaKeyProviderFactor
     }
 
     @Override
-    public void init(Config.Scope config) {
-    }
-
-    @Override
-    public void postInit(KeycloakSessionFactory factory) {
-    }
-
-    @Override
-    public void close() {
-    }
-
-    @Override
     public String getId() {
         return ID;
     }
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java
index 76b7ea8..1d416d2 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java
@@ -17,86 +17,67 @@
 
 package org.keycloak.keys;
 
-import java.util.Collections;
-import java.util.List;
-
-import javax.crypto.SecretKey;
-
 import org.keycloak.common.util.Base64Url;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.JavaAlgorithm;
+import org.keycloak.crypto.KeyStatus;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import javax.crypto.SecretKey;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public abstract class GeneratedSecretKeyProvider implements SecretKeyProvider {
-
-    private final boolean enabled;
-
-    private final boolean active;
+public abstract class GeneratedSecretKeyProvider implements KeyProvider {
 
+    private final KeyStatus status;
     private final ComponentModel model;
     private final String kid;
     private final SecretKey secretKey;
+    private final KeyUse use;
+    private String type;
+    private final String algorithm;
 
-    public GeneratedSecretKeyProvider(ComponentModel model) {
-        this.enabled = model.get(Attributes.ENABLED_KEY, true);
-        this.active = model.get(Attributes.ACTIVE_KEY, true);
+    public GeneratedSecretKeyProvider(ComponentModel model, KeyUse use, String type, String algorithm) {
+        this.status = KeyStatus.from(model.get(Attributes.ACTIVE_KEY, true), model.get(Attributes.ENABLED_KEY, true));
         this.kid = model.get(Attributes.KID_KEY);
         this.model = model;
+        this.use = use;
+        this.type = type;
+        this.algorithm = algorithm;
 
         if (model.hasNote(SecretKey.class.getName())) {
             secretKey = model.getNote(SecretKey.class.getName());
         } else {
-            secretKey = KeyUtils.loadSecretKey(Base64Url.decode(model.get(Attributes.SECRET_KEY)), getJavaAlgorithmName());
+            secretKey = KeyUtils.loadSecretKey(Base64Url.decode(model.get(Attributes.SECRET_KEY)), JavaAlgorithm.getJavaAlgorithm(algorithm));
             model.setNote(SecretKey.class.getName(), secretKey);
         }
     }
 
     @Override
-    public SecretKey getSecretKey() {
-        return isActive() ? secretKey : null;
-    }
+    public List<KeyWrapper> getKeys() {
+        KeyWrapper key = new KeyWrapper();
 
-    @Override
-    public SecretKey getSecretKey(String kid) {
-        return isEnabled() && kid.equals(this.kid) ? secretKey : null;
-    }
+        key.setProviderId(model.getId());
+        key.setProviderPriority(model.get("priority", 0l));
 
-    @Override
-    public String getKid() {
-        return isActive() ? kid : null;
-    }
+        key.setKid(kid);
+        key.setUse(use);
+        key.setType(type);
+        key.setAlgorithms(algorithm);
+        key.setStatus(status);
+        key.setSecretKey(secretKey);
 
-    @Override
-    public List<SecretKeyMetadata> getKeyMetadata() {
-        if (kid != null && secretKey != null) {
-            SecretKeyMetadata k = new SecretKeyMetadata();
-            k.setProviderId(model.getId());
-            k.setProviderPriority(model.get(Attributes.PRIORITY_KEY, 0l));
-            k.setKid(kid);
-            if (isActive()) {
-                k.setStatus(KeyMetadata.Status.ACTIVE);
-            } else if (isEnabled()) {
-                k.setStatus(KeyMetadata.Status.PASSIVE);
-            } else {
-                k.setStatus(KeyMetadata.Status.DISABLED);
-            }
-            return Collections.singletonList(k);
-        } else {
-            return Collections.emptyList();
-        }
+        return Collections.singletonList(key);
     }
 
     @Override
     public void close() {
     }
 
-    private boolean isEnabled() {
-        return secretKey != null && enabled;
-    }
-
-    private boolean isActive() {
-        return isEnabled() && active;
-    }
 }
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java
index 3211cfc..c6c5d41 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java
@@ -66,17 +66,5 @@ public abstract class GeneratedSecretKeyProviderFactory<T extends KeyProvider> i
 
     protected abstract Logger logger();
 
-    @Override
-    public void init(Config.Scope config) {
-    }
-
-    @Override
-    public void postInit(KeycloakSessionFactory factory) {
-    }
-
-    @Override
-    public void close() {
-    }
-
     protected abstract int getDefaultKeySize();
 }
diff --git a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java
index 6fd7a92..67968a4 100644
--- a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java
@@ -20,6 +20,7 @@ package org.keycloak.keys;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.PemUtils;
 import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.models.RealmModel;
 
 import java.security.KeyPair;
@@ -38,7 +39,7 @@ public class ImportedRsaKeyProvider extends AbstractRsaKeyProvider {
     }
 
     @Override
-    public Keys loadKeys(RealmModel realm, ComponentModel model) {
+    public KeyWrapper loadKey(RealmModel realm, ComponentModel model) {
         String privateRsaKeyPem = model.getConfig().getFirst(Attributes.PRIVATE_KEY_KEY);
         String certificatePem = model.getConfig().getFirst(Attributes.CERTIFICATE_KEY);
 
@@ -48,9 +49,7 @@ public class ImportedRsaKeyProvider extends AbstractRsaKeyProvider {
         KeyPair keyPair = new KeyPair(publicKey, privateKey);
         X509Certificate certificate = PemUtils.decodeCertificate(certificatePem);
 
-        String kid = KeyUtils.createKeyId(keyPair.getPublic());
-
-        return new Keys(kid, keyPair, certificate);
+        return createKeyWrapper(keyPair, certificate);
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java
index 5dbe4bc..d46a77a 100644
--- a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java
@@ -17,14 +17,12 @@
 
 package org.keycloak.keys;
 
-import org.keycloak.Config;
 import org.keycloak.common.util.CertificateUtils;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.PemUtils;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.component.ComponentValidationException;
 import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel;
 import org.keycloak.provider.ConfigurationValidationHelper;
 import org.keycloak.provider.ProviderConfigProperty;
@@ -107,18 +105,6 @@ public class ImportedRsaKeyProviderFactory extends AbstractRsaKeyProviderFactory
     }
 
     @Override
-    public void init(Config.Scope config) {
-    }
-
-    @Override
-    public void postInit(KeycloakSessionFactory factory) {
-    }
-
-    @Override
-    public void close() {
-    }
-
-    @Override
     public String getId() {
         return ID;
     }
diff --git a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
index 8c98bb4..ba5dfc6 100644
--- a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
@@ -17,23 +17,16 @@
 
 package org.keycloak.keys;
 
-import org.jboss.logging.Logger;
 import org.keycloak.common.util.CertificateUtils;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.models.RealmModel;
 
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.security.KeyPair;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
+import java.security.*;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 
@@ -42,14 +35,12 @@ import java.security.cert.X509Certificate;
  */
 public class JavaKeystoreKeyProvider extends AbstractRsaKeyProvider {
 
-    private static final Logger logger = Logger.getLogger(JavaKeystoreKeyProvider.class);
-
     public JavaKeystoreKeyProvider(RealmModel realm, ComponentModel model) {
         super(realm, model);
     }
 
     @Override
-    protected Keys loadKeys(RealmModel realm, ComponentModel model) {
+    protected KeyWrapper loadKey(RealmModel realm, ComponentModel model) {
         try {
             KeyStore keyStore = KeyStore.getInstance("JKS");
             keyStore.load(new FileInputStream(model.get(JavaKeystoreKeyProviderFactory.KEYSTORE_KEY)), model.get(JavaKeystoreKeyProviderFactory.KEYSTORE_PASSWORD_KEY).toCharArray());
@@ -64,9 +55,7 @@ public class JavaKeystoreKeyProvider extends AbstractRsaKeyProvider {
                 certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, realm.getName());
             }
 
-            String kid = KeyUtils.createKeyId(keyPair.getPublic());
-
-            return new Keys(kid, keyPair, certificate);
+            return createKeyWrapper(keyPair, certificate);
         } catch (KeyStoreException kse) {
             throw new RuntimeException("KeyStore error on server. " + kse.getMessage(), kse);
         } catch (FileNotFoundException fnfe) {
diff --git a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
index 51b726a..325be9e 100644
--- a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
@@ -77,7 +77,7 @@ public class JavaKeystoreKeyProviderFactory extends AbstractRsaKeyProviderFactor
 
         try {
             new JavaKeystoreKeyProvider(session.getContext().getRealm(), model)
-                    .loadKeys(session.getContext().getRealm(), model);
+                    .loadKey(session.getContext().getRealm(), model);
         } catch (Throwable t) {
             logger.error("Failed to load keys.", t);
             throw new ComponentValidationException("Failed to load keys. " + t.getMessage(), t);
@@ -95,18 +95,6 @@ public class JavaKeystoreKeyProviderFactory extends AbstractRsaKeyProviderFactor
     }
 
     @Override
-    public void init(Config.Scope config) {
-    }
-
-    @Override
-    public void postInit(KeycloakSessionFactory factory) {
-    }
-
-    @Override
-    public void close() {
-    }
-
-    @Override
     public String getId() {
         return ID;
     }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
index 6fa6705..c1952a5 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
@@ -26,7 +26,6 @@ import org.keycloak.forms.login.LoginFormsProvider;
 import org.keycloak.jose.jwk.JSONWebKeySet;
 import org.keycloak.jose.jwk.JWK;
 import org.keycloak.jose.jwk.JWKBuilder;
-import org.keycloak.keys.KeyMetadata;
 import org.keycloak.keys.RsaKeyMetadata;
 import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
@@ -195,7 +194,7 @@ public class OIDCLoginProtocolService {
     @Produces(MediaType.APPLICATION_JSON)
     @NoCache
     public Response certs() {
-        List<RsaKeyMetadata> publicKeys = session.keys().getRsaKeys(realm, false);
+        List<RsaKeyMetadata> publicKeys = session.keys().getRsaKeys(realm);
         JWK[] keys = new JWK[publicKeys.size()];
 
         int i = 0;
diff --git a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
index 2261d52..b3b6d6a 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
@@ -19,6 +19,8 @@ package org.keycloak.protocol.saml.installation;
 
 import org.keycloak.Config;
 import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.KeyStatus;
+import org.keycloak.dom.saml.v2.metadata.KeyTypes;
 import org.keycloak.keys.RsaKeyMetadata;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
@@ -27,6 +29,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.ClientInstallationProvider;
 import org.keycloak.protocol.saml.SamlClient;
 import org.keycloak.protocol.saml.SamlProtocol;
+import org.keycloak.saml.SPMetadataDescriptor;
 import org.keycloak.services.resources.RealmsResource;
 
 import javax.ws.rs.core.MediaType;
@@ -35,9 +38,6 @@ import javax.ws.rs.core.UriBuilder;
 import java.net.URI;
 import java.util.Set;
 import java.util.TreeSet;
-import org.keycloak.dom.saml.v2.metadata.KeyTypes;
-import org.keycloak.keys.KeyMetadata;
-import org.keycloak.saml.SPMetadataDescriptor;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -90,8 +90,8 @@ public class SamlIDPDescriptorClientInstallation implements ClientInstallationPr
         // keys
         Set<RsaKeyMetadata> keys = new TreeSet<>((o1, o2) -> o1.getStatus() == o2.getStatus() // Status can be only PASSIVE OR ACTIVE, push PASSIVE to end of list
           ? (int) (o2.getProviderPriority() - o1.getProviderPriority())
-          : (o1.getStatus() == KeyMetadata.Status.PASSIVE ? 1 : -1));
-        keys.addAll(session.keys().getRsaKeys(realm, false));
+          : (o1.getStatus() == KeyStatus.PASSIVE ? 1 : -1));
+        keys.addAll(session.keys().getRsaKeys(realm));
         for (RsaKeyMetadata key : keys) {
             addKeyInfo(sb, key, KeyTypes.SIGNING.value());
         }
diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
index e6f1833..b98727c 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -23,6 +23,7 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.common.VerificationException;
 import org.keycloak.common.util.PemUtils;
 import org.keycloak.common.util.StreamUtil;
+import org.keycloak.crypto.KeyStatus;
 import org.keycloak.dom.saml.v2.SAML2Object;
 import org.keycloak.dom.saml.v2.assertion.BaseIDAbstractType;
 import org.keycloak.dom.saml.v2.assertion.NameIDType;
@@ -80,7 +81,6 @@ import java.util.Set;
 import java.util.TreeSet;
 import org.keycloak.common.util.StringPropertyReplacer;
 import org.keycloak.dom.saml.v2.metadata.KeyTypes;
-import org.keycloak.keys.KeyMetadata;
 import org.keycloak.rotation.HardcodedKeyLocator;
 import org.keycloak.rotation.KeyLocator;
 import org.keycloak.saml.SPMetadataDescriptor;
@@ -591,8 +591,8 @@ public class SamlService extends AuthorizationEndpointBase {
         StringBuilder keysString = new StringBuilder();
         Set<RsaKeyMetadata> keys = new TreeSet<>((o1, o2) -> o1.getStatus() == o2.getStatus() // Status can be only PASSIVE OR ACTIVE, push PASSIVE to end of list
           ? (int) (o2.getProviderPriority() - o1.getProviderPriority())
-          : (o1.getStatus() == KeyMetadata.Status.PASSIVE ? 1 : -1));
-        keys.addAll(session.keys().getRsaKeys(realm, false));
+          : (o1.getStatus() == KeyStatus.PASSIVE ? 1 : -1));
+        keys.addAll(session.keys().getRsaKeys(realm));
         for (RsaKeyMetadata key : keys) {
             addKeyInfo(keysString, key, KeyTypes.SIGNING.value());
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java b/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
index 87bb486..da0f3cb 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
@@ -19,9 +19,9 @@ package org.keycloak.services.resources.admin;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.KeyWrapper;
 import org.keycloak.jose.jws.AlgorithmType;
 import org.keycloak.keys.SecretKeyMetadata;
-import org.keycloak.keys.RsaKeyMetadata;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeyManager;
 import org.keycloak.models.RealmModel;
@@ -58,48 +58,30 @@ public class KeyResource {
     public KeysMetadataRepresentation getKeyMetadata() {
         auth.realm().requireViewRealm();
 
-        KeyManager keystore = session.keys();
-
         KeysMetadataRepresentation keys = new KeysMetadataRepresentation();
+        keys.setKeys(new LinkedList<>());
+        keys.setActive(new HashMap<>());
 
-        Map<String, String> active = new HashMap<>();
-        active.put(AlgorithmType.RSA.name(), keystore.getActiveRsaKey(realm).getKid());
-        active.put(AlgorithmType.HMAC.name(), keystore.getActiveHmacKey(realm).getKid());
-        active.put(AlgorithmType.AES.name(), keystore.getActiveAesKey(realm).getKid());
-        keys.setActive(active);
-
-        List<KeysMetadataRepresentation.KeyMetadataRepresentation> l = new LinkedList<>();
-        for (RsaKeyMetadata m : session.keys().getRsaKeys(realm, true)) {
-            KeysMetadataRepresentation.KeyMetadataRepresentation r = new KeysMetadataRepresentation.KeyMetadataRepresentation();
-            r.setProviderId(m.getProviderId());
-            r.setProviderPriority(m.getProviderPriority());
-            r.setKid(m.getKid());
-            r.setStatus(m.getStatus() != null ? m.getStatus().name() : null);
-            r.setType(AlgorithmType.RSA.name());
-            r.setPublicKey(PemUtils.encodeKey(m.getPublicKey()));
-            r.setCertificate(PemUtils.encodeCertificate(m.getCertificate()));
-            l.add(r);
-        }
-        for (SecretKeyMetadata m : session.keys().getHmacKeys(realm, true)) {
+        for (KeyWrapper key : session.keys().getKeys(realm)) {
             KeysMetadataRepresentation.KeyMetadataRepresentation r = new KeysMetadataRepresentation.KeyMetadataRepresentation();
-            r.setProviderId(m.getProviderId());
-            r.setProviderPriority(m.getProviderPriority());
-            r.setKid(m.getKid());
-            r.setStatus(m.getStatus() != null ? m.getStatus().name() : null);
-            r.setType(AlgorithmType.HMAC.name());
-            l.add(r);
-        }
-        for (SecretKeyMetadata m : session.keys().getAesKeys(realm, true)) {
-            KeysMetadataRepresentation.KeyMetadataRepresentation r = new KeysMetadataRepresentation.KeyMetadataRepresentation();
-            r.setProviderId(m.getProviderId());
-            r.setProviderPriority(m.getProviderPriority());
-            r.setKid(m.getKid());
-            r.setStatus(m.getStatus() != null ? m.getStatus().name() : null);
-            r.setType(AlgorithmType.AES.name());
-            l.add(r);
-        }
+            r.setProviderId(key.getProviderId());
+            r.setProviderPriority(key.getProviderPriority());
+            r.setKid(key.getKid());
+            r.setStatus(key.getStatus() != null ? key.getStatus().name() : null);
+            r.setType(key.getType());
+            r.setAlgorithms(key.getAlgorithms());
+            r.setPublicKey(key.getVerifyKey() != null ? PemUtils.encodeKey(key.getVerifyKey()) : null);
+            r.setCertificate(key.getCertificate() != null ? PemUtils.encodeCertificate(key.getCertificate()) : null);
+            keys.getKeys().add(r);
 
-        keys.setKeys(l);
+            if (key.getStatus().isActive()) {
+                for (String a : key.getAlgorithms()) {
+                    if (!keys.getActive().containsKey(a)) {
+                        keys.getActive().put(a, key.getKid());
+                    }
+                }
+            }
+        }
 
         return keys;
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
index 208ae91..7bff5ac 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
@@ -23,6 +23,7 @@ import org.keycloak.admin.client.resource.ClientScopeResource;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.RoleResource;
 import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.crypto.Algorithm;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ClientScopeRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
@@ -255,7 +256,7 @@ public class ApiUtil {
 
     public static KeysMetadataRepresentation.KeyMetadataRepresentation findActiveKey(RealmResource realm) {
         KeysMetadataRepresentation keyMetadata = realm.keys().getKeyMetadata();
-        String activeKid = keyMetadata.getActive().get("RSA");
+        String activeKid = keyMetadata.getActive().get(Algorithm.RS256);
         for (KeysMetadataRepresentation.KeyMetadataRepresentation rep : keyMetadata.getKeys()) {
             if (rep.getKid().equals(activeKid)) {
                 return rep;
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
index afe2f51..2862755 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
@@ -1,6 +1,7 @@
 package org.keycloak.testsuite.util;
 
 import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.representations.idm.KeysMetadataRepresentation;
 
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
@@ -39,4 +40,15 @@ public class KeyUtils {
             throw new RuntimeException(e);
         }
     }
+
+    public static KeysMetadataRepresentation.KeyMetadataRepresentation getActiveKey(KeysMetadataRepresentation keys, String algorithm) {
+        String kid = keys.getActive().get(algorithm);
+        for (KeysMetadataRepresentation.KeyMetadataRepresentation k : keys.getKeys()) {
+            if (k.getKid().equals(kid)) {
+                return k;
+            }
+        }
+        throw new RuntimeException("Active key not found");
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
index 9e0f12d..21186bd 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
@@ -38,6 +38,7 @@ import org.keycloak.common.VerificationException;
 import org.keycloak.common.util.KeystoreUtil;
 import org.keycloak.common.util.PemUtils;
 import org.keycloak.constants.AdapterConstants;
+import org.keycloak.crypto.Algorithm;
 import org.keycloak.jose.jwk.JSONWebKeySet;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
@@ -1099,7 +1100,7 @@ public class OAuthClient {
     public PublicKey getRealmPublicKey(String realm) {
         if (!publicKeys.containsKey(realm)) {
             KeysMetadataRepresentation keyMetadata = adminClient.realms().realm(realm).keys().getKeyMetadata();
-            String activeKid = keyMetadata.getActive().get("RSA");
+            String activeKid = keyMetadata.getActive().get(Algorithm.RS256);
             PublicKey publicKey = null;
             for (KeysMetadataRepresentation.KeyMetadataRepresentation rep : keyMetadata.getKeys()) {
                 if (rep.getKid().equals(activeKid)) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java
index a1cb309..bd10c3a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java
@@ -42,7 +42,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.common.util.StreamUtil;
 import org.keycloak.common.util.Time;
 import org.keycloak.constants.AdapterConstants;
-import org.keycloak.jose.jws.AlgorithmType;
+import org.keycloak.crypto.Algorithm;
 import org.keycloak.keys.KeyProvider;
 import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
@@ -308,7 +308,7 @@ public class OIDCPublicKeyRotationAdapterTest extends AbstractServletsAdapterTes
 
     private String getActiveKeyProvider() {
         KeysMetadataRepresentation keyMetadata = adminClient.realm(DEMO).keys().getKeyMetadata();
-        String activeKid = keyMetadata.getActive().get(AlgorithmType.RSA.name());
+        String activeKid = keyMetadata.getActive().get(Algorithm.RS256);
         for (KeysMetadataRepresentation.KeyMetadataRepresentation rep : keyMetadata.getKeys()) {
             if (rep.getKid().equals(activeKid)) {
                 return rep.getProviderId();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java
index 83496a3..f98a5fc 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java
@@ -28,6 +28,7 @@ import org.junit.Test;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.common.util.*;
 import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.crypto.Algorithm;
 import org.keycloak.keys.KeyProvider;
 import org.keycloak.keys.PublicKeyStorageUtils;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
@@ -293,7 +294,7 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest {
 
 
     private void rotateKeys() {
-        String activeKid = providerRealm().keys().getKeyMetadata().getActive().get("RSA");
+        String activeKid = providerRealm().keys().getKeyMetadata().getActive().get(Algorithm.RS256);
 
         // Rotate public keys on the parent broker
         String realmId = providerRealm().toRepresentation().getId();
@@ -308,7 +309,7 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest {
         assertEquals(201, response.getStatus());
         response.close();
 
-        String updatedActiveKid = providerRealm().keys().getKeyMetadata().getActive().get("RSA");
+        String updatedActiveKid = providerRealm().keys().getKeyMetadata().getActive().get(Algorithm.RS256);
         assertNotEquals(activeKid, updatedActiveKid);
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
index e447998..6887f74 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
@@ -2,10 +2,12 @@ package org.keycloak.testsuite.broker;
 
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
+import org.keycloak.crypto.Algorithm;
 import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
 import org.keycloak.protocol.saml.SamlConfigAttributes;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.KeysMetadataRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.common.util.DocumentUtil;
@@ -16,6 +18,7 @@ import org.keycloak.testsuite.arquillian.SuiteContext;
 import org.keycloak.testsuite.saml.AbstractSamlTest;
 import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
 import org.keycloak.testsuite.updaters.IdentityProviderAttributeUpdater;
+import org.keycloak.testsuite.util.KeyUtils;
 import org.keycloak.testsuite.util.SamlClient;
 import org.keycloak.testsuite.util.SamlClient.Binding;
 import org.keycloak.testsuite.util.SamlClientBuilder;
@@ -66,7 +69,7 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
         public List<ClientRepresentation> createProviderClients(SuiteContext suiteContext) {
             List<ClientRepresentation> clientRepresentationList = super.createProviderClients(suiteContext);
 
-            String consumerCert = adminClient.realm(consumerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+            String consumerCert = KeyUtils.getActiveKey(adminClient.realm(consumerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
             Assert.assertThat(consumerCert, Matchers.notNullValue());
 
             for (ClientRepresentation client : clientRepresentationList) {
@@ -93,7 +96,7 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
         public IdentityProviderRepresentation setUpIdentityProvider(SuiteContext suiteContext) {
             IdentityProviderRepresentation result = super.setUpIdentityProvider(suiteContext);
 
-            String providerCert = adminClient.realm(providerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+            String providerCert = KeyUtils.getActiveKey(adminClient.realm(providerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
             Assert.assertThat(providerCert, Matchers.notNullValue());
 
             Map<String, String> config = result.getConfig();
@@ -121,10 +124,10 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
         final ClientResource clientResource = realmsResouce().realm(bc.providerRealmName()).clients().get(client.getId());
         Assert.assertThat(clientResource, Matchers.notNullValue());
 
-        String providerCert = adminClient.realm(bc.providerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+        String providerCert = KeyUtils.getActiveKey(adminClient.realm(bc.providerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
         Assert.assertThat(providerCert, Matchers.notNullValue());
 
-        String consumerCert = adminClient.realm(bc.consumerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+        String consumerCert = KeyUtils.getActiveKey(adminClient.realm(bc.consumerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
         Assert.assertThat(consumerCert, Matchers.notNullValue());
 
         try (Closeable idpUpdater = new IdentityProviderAttributeUpdater(identityProviderResource)
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java
index efddeea..4734ffd 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java
@@ -24,6 +24,8 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.common.util.Base64Url;
 import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
 import org.keycloak.jose.jws.AlgorithmType;
 import org.keycloak.keys.GeneratedHmacKeyProviderFactory;
 import org.keycloak.keys.KeyProvider;
@@ -90,14 +92,14 @@ public class GeneratedHmacKeyProviderTest extends AbstractKeycloakTest {
 
         KeysMetadataRepresentation.KeyMetadataRepresentation key = null;
         for (KeysMetadataRepresentation.KeyMetadataRepresentation k : keys.getKeys()) {
-            if (k.getType().equals(AlgorithmType.HMAC.name())) {
+            if (k.getAlgorithms().contains(Algorithm.HS256)) {
                 key = k;
                 break;
             }
         }
 
         assertEquals(id, key.getProviderId());
-        assertEquals(AlgorithmType.HMAC.name(), key.getType());
+        assertEquals(KeyType.OCT, key.getType());
         assertEquals(priority, key.getProviderPriority());
 
         ComponentRepresentation component = testingClient.server("test").fetch(RunHelpers.internalComponent(id));
@@ -125,14 +127,14 @@ public class GeneratedHmacKeyProviderTest extends AbstractKeycloakTest {
 
         KeysMetadataRepresentation.KeyMetadataRepresentation key = null;
         for (KeysMetadataRepresentation.KeyMetadataRepresentation k : keys.getKeys()) {
-            if (k.getType().equals(AlgorithmType.HMAC.name())) {
+            if (k.getAlgorithms().contains(Algorithm.HS256)) {
                 key = k;
                 break;
             }
         }
 
         assertEquals(id, key.getProviderId());
-        assertEquals(AlgorithmType.HMAC.name(), key.getType());
+        assertEquals(KeyType.OCT, key.getType());
         assertEquals(priority, key.getProviderPriority());
 
         ComponentRepresentation component = testingClient.server("test").fetch(RunHelpers.internalComponent(id));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java
index e8d11ec..47e850e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java
@@ -24,6 +24,7 @@ import org.keycloak.common.util.CertificateUtils;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.Algorithm;
 import org.keycloak.jose.jws.AlgorithmType;
 import org.keycloak.keys.Attributes;
 import org.keycloak.keys.ImportedRsaKeyProviderFactory;
@@ -90,7 +91,7 @@ public class ImportedRsaKeyProviderTest extends AbstractKeycloakTest {
 
         KeysMetadataRepresentation keys = adminClient.realm("test").keys().getKeyMetadata();
 
-        assertEquals(kid, keys.getActive().get(AlgorithmType.RSA.name()));
+        assertEquals(kid, keys.getActive().get(Algorithm.RS256));
 
         KeysMetadataRepresentation.KeyMetadataRepresentation key = keys.getKeys().get(0);
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java
index 9700a29..cbc8db5 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java
@@ -30,6 +30,7 @@ import org.keycloak.common.VerificationException;
 import org.keycloak.common.util.KeyUtils;
 import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.Algorithm;
 import org.keycloak.keys.Attributes;
 import org.keycloak.keys.GeneratedHmacKeyProviderFactory;
 import org.keycloak.keys.KeyProvider;
@@ -218,7 +219,7 @@ public class KeyRotationTest extends AbstractKeycloakTest {
         PublicKey keys2 = createKeys2();
 
         KeysMetadataRepresentation keyMetadata = adminClient.realm("test").keys().getKeyMetadata();
-        assertEquals(PemUtils.encodeKey(keys2), keyMetadata.getKeys().get(0).getPublicKey());
+        assertEquals(PemUtils.encodeKey(keys2), org.keycloak.testsuite.util.KeyUtils.getActiveKey(keyMetadata, Algorithm.RS256).getPublicKey());
 
         dropKeys1();
         dropKeys2();
@@ -227,7 +228,7 @@ public class KeyRotationTest extends AbstractKeycloakTest {
     @Test
     public void rotateKeys() throws InterruptedException {
         for (int i = 0; i < 10; i++) {
-            String activeKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get("RSA");
+            String activeKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get(Algorithm.RS256);
 
             // Rotate public keys on the parent broker
             String realmId = adminClient.realm("test").toRepresentation().getId();
@@ -244,7 +245,7 @@ public class KeyRotationTest extends AbstractKeycloakTest {
             getCleanup().addComponentId(newId);
             response.close();
 
-            String updatedActiveKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get("RSA");
+            String updatedActiveKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get(Algorithm.RS256);
             assertNotEquals(activeKid, updatedActiveKid);
         }
     }
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java
index b2fdf8f..2ab996d 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java
@@ -16,8 +16,6 @@
  */
 package org.keycloak.testsuite;
 
-import org.jboss.logging.Logger;
-
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
@@ -29,8 +27,6 @@ import java.net.URI;
  */
 public class ApiUtil {
 
-    private static final Logger log = Logger.getLogger(ApiUtil.class);
-
     public static String getCreatedId(Response response) {
         URI location = response.getLocation();
         if (!response.getStatusInfo().equals(Status.CREATED)) {
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index c13aecd..a062db2 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -1388,7 +1388,6 @@ authz-evaluation-authorization-data.tooltip=Represents a token carrying authoriz
 authz-show-authorization-data=Show Authorization Data
 
 keys=Keys
-all=All
 status=Status
 keystore=Keystore
 keystores=Keystores
@@ -1396,6 +1395,10 @@ add-keystore=Add Keystore
 add-keystore.placeholder=Add keystore...
 view=View
 active=Active
+passive=Passive
+disabled=Disabled
+algorithms=Algorithms
+providerHelpText=Provider description
 
 Sunday=Sunday
 Monday=Monday
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/app.js b/themes/src/main/resources/theme/base/admin/resources/js/app.js
index 6aaff54..f03208c 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -289,8 +289,8 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'RealmKeysCtrl'
         })
-        .when('/realms/:realm/keys/list', {
-            templateUrl : resourceUrl + '/partials/realm-keys-list.html',
+        .when('/realms/:realm/keys/passive', {
+            templateUrl : resourceUrl + '/partials/realm-keys-passive.html',
             resolve : {
                 realm : function(RealmLoader) {
                     return RealmLoader();
@@ -304,6 +304,21 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'RealmKeysCtrl'
         })
+        .when('/realms/:realm/keys/disabled', {
+                    templateUrl : resourceUrl + '/partials/realm-keys-disabled.html',
+                    resolve : {
+                        realm : function(RealmLoader) {
+                            return RealmLoader();
+                        },
+                        serverInfo : function(ServerInfoLoader) {
+                            return ServerInfoLoader();
+                        },
+                        keys: function(RealmKeysLoader) {
+                            return RealmKeysLoader();
+                        }
+                    },
+                    controller : 'RealmKeysCtrl'
+                })
         .when('/realms/:realm/keys/providers', {
             templateUrl : resourceUrl + '/partials/realm-keys-providers.html',
             resolve : {
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html
index 81215d0..2bc75a8 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html
@@ -1,25 +1,61 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
 <div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
     <kc-tabs-realm></kc-tabs-realm>
 
     <ul class="nav nav-tabs nav-tabs-pf">
         <li class="active"><a href="#/realms/{{realm.realm}}/keys">{{:: 'active' | translate}}</a></li>
-        <li><a href="#/realms/{{realm.realm}}/keys/list">{{:: 'all' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/keys/passive">{{:: 'passive' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/keys/disabled">{{:: 'disabled' | translate}}</a></li>
         <li><a href="#/realms/{{realm.realm}}/keys/providers">{{:: 'providers' | translate}}</a></li>
     </ul>
 
     <table class="table table-striped table-bordered">
         <thead>
         <tr>
+            <th class="kc-table-actions" colspan="7">
+                <div class="form-inline">
+                    <div class="form-group">
+                        <div class="input-group">
+                            <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search" class="form-control search"">
+                            <div class="input-group-addon">
+                                <i class="fa fa-search"></i>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </th>
+        </tr>
+        <tr>
+            <th>{{:: 'algorithms' | translate}}</th>
             <th>{{:: 'type' | translate}}</th>
             <th>{{:: 'kid' | translate}}</th>
+            <th>{{:: 'priority' | translate}}</th>
             <th>{{:: 'provider' | translate}}</th>
             <th colspan="2">{{:: 'publicKeys' | translate}}</th>
         </tr>
         </thead>
         <tbody>
-        <tr ng-repeat="key in active">
+        <tr ng-repeat="key in keys | filter:search | filter:{status:'ACTIVE'}">
+            <td>{{key.algorithm.sort().join(', ')}}</td>
             <td>{{key.type}}</td>
             <td>{{key.kid}}</td>
+            <td>{{key.providerPriority}}</td>
             <td><a href="#/realms/{{realm.realm}}/keys/providers/{{key.provider.providerId}}/{{key.provider.id}}">{{key.provider.name}}</a></td>
 
             <td data-ng-show="key.type === 'RSA'" class="kc-action-cell" data-ng-click="viewKey(key.publicKey)">{{:: 'publicKey' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-passive.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-passive.html
new file mode 100755
index 0000000..461dcc1
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-passive.html
@@ -0,0 +1,71 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <kc-tabs-realm></kc-tabs-realm>
+
+    <ul class="nav nav-tabs nav-tabs-pf">
+        <li><a href="#/realms/{{realm.realm}}/keys">{{:: 'active' | translate}}</a></li>
+        <li class="active"><a href="#/realms/{{realm.realm}}/keys/passive">{{:: 'passive' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/keys/disabled">{{:: 'disabled' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/keys/providers">{{:: 'providers' | translate}}</a></li>
+    </ul>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+        <tr>
+            <th class="kc-table-actions" colspan="7">
+                <div class="form-inline">
+                    <div class="form-group">
+                        <div class="input-group">
+                            <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search" class="form-control search"">
+                            <div class="input-group-addon">
+                                <i class="fa fa-search"></i>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </th>
+        </tr>
+        <tr>
+            <th>{{:: 'algorithms' | translate}}</th>
+            <th>{{:: 'type' | translate}}</th>
+            <th>{{:: 'kid' | translate}}</th>
+            <th>{{:: 'priority' | translate}}</th>
+            <th>{{:: 'provider' | translate}}</th>
+            <th colspan="2">{{:: 'publicKeys' | translate}}</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="key in keys | filter:search | filter:{status:'PASSIVE'}">
+            <td>{{key.algorithm.sort().join(', ')}}</td>
+            <td>{{key.type}}</td>
+            <td>{{key.kid}}</td>
+            <td>{{key.providerPriority}}</td>
+            <td><a href="#/realms/{{realm.realm}}/keys/providers/{{key.provider.providerId}}/{{key.provider.id}}">{{key.provider.name}}</a></td>
+
+            <td data-ng-show="key.type === 'RSA'" class="kc-action-cell" data-ng-click="viewKey(key.publicKey)">{{:: 'publicKey' | translate}}</td>
+            <td data-ng-show="key.type === 'RSA'" class="kc-action-cell" data-ng-click="viewKey(key.certificate)">{{:: 'certificate' | translate}}</td>
+
+            <td data-ng-show="key.type !== 'RSA'" colspan="2"></td>
+        </tr>
+        </tbody>
+    </table>
+
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
index fceea49..c303a38 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
@@ -20,16 +20,26 @@
 
     <ul class="nav nav-tabs nav-tabs-pf">
         <li><a href="#/realms/{{realm.realm}}/keys">{{:: 'active' | translate}}</a></li>
-        <li><a href="#/realms/{{realm.realm}}/keys/list">{{:: 'all' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/keys/passive">{{:: 'passive' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/keys/disabled">{{:: 'disabled' | translate}}</a></li>
         <li class="active"><a href="#/realms/{{realm.realm}}/keys/providers">{{:: 'providers' | translate}}</a></li>
     </ul>
 
     <table class="table table-striped table-bordered">
         <thead>
-        <tr ng-show="providers.length > 0 && access.manageRealm">
-            <th colspan="7" class="kc-table-actions">
-                <div class="pull-right">
-                    <div>
+        <tr>
+            <th class="kc-table-actions" colspan="7">
+                <div class="form-inline">
+                    <div class="form-group">
+                        <div class="input-group">
+                            <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search" class="form-control search">
+                            <div class="input-group-addon">
+                                <i class="fa fa-search"></i>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="pull-right" data-ng-show="access.manageClients">
                         <select class="form-control" ng-model="selectedProvider"
                                 ng-options="p.id for p in providers"
                                 data-ng-change="addProvider(selectedProvider); selectedProvider = null">
@@ -40,20 +50,18 @@
             </th>
         </tr>
         <tr data-ng-show="instances && instances.length > 0">
-            <th>{{:: 'type' | translate}}</th>
             <th>{{:: 'name' | translate}}</th>
-            <th>{{:: 'id' | translate}}</th>
             <th>{{:: 'provider' | translate}}</th>
+            <th>{{:: 'providerHelpText' | translate}}</th>
             <th>{{:: 'priority' | translate}}</th>
             <th colspan="2">{{:: 'actions' | translate}}</th>
         </tr>
         </thead>
         <tbody>
-        <tr ng-repeat="instance in instances">
-            <td>{{instance.provider.metadata.algorithmType}}</td>
-            <td>{{instance.name}}</td>
-            <td><a href="#/realms/{{realm.realm}}/keys/providers/{{instance.providerId}}/{{instance.id}}">{{instance.id}}</a></td>
+        <tr ng-repeat="instance in instances | filter:search">
+            <td><a href="#/realms/{{realm.realm}}/keys/providers/{{instance.providerId}}/{{instance.id}}">{{instance.name}}</a></td>
             <td>{{instance.providerId}}</td>
+            <td>{{instance.provider.helpText}}</td>
             <td>{{instance.config['priority'][0]}}</td>
             <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/keys/providers/{{instance.providerId}}/{{instance.id}}">{{:: 'edit' | translate}}</td>
             <td class="kc-action-cell" ng-show="instances.length > 1" data-ng-click="removeInstance(instance)">{{:: 'delete' | translate}}</td>