[java-oidc-common] 01/03: JCOMOIDC-62 - Create new credential type for client_secret

Phil Smart philip.smart at jisc.ac.uk
Fri Jan 27 15:14:58 UTC 2023


This is an automated email from the git hooks/post-receive script.

philsmart pushed a commit to branch dev/JCOMOIDC-62
in repository java-oidc-common.

View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=f45f0b248d937da1517fafb1ef10b8a4c8a52909

commit f45f0b248d937da1517fafb1ef10b8a4c8a52909
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Jan 23 13:30:46 2023 +0000

    JCOMOIDC-62 - Create new credential type for client_secret
    
     - Change to a simple client secret credential
     - Modify touch points and call sites to be compatible
     - Modify encryption, decryption, and signature classes to use the new
    credential type
     - Add new 'alg' and 'enc' criteria to the encryption params resolver.
     - Add new 'alg' and 'enc' criteria to the JWE decrypter.
     - Modify the client secret resolver to derive the correct key for the
    given algorithm inputs
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-62
---
 .../oidc/security}/CredentialConversionUtil.java   |   2 +-
 .../credential/BasicNimbusSecretCredential.java    |   1 +
 .../credential/ClientSecretCredential.java         |  72 ++++
 .../credential/DefaultClientSecretCredential.java  | 111 ++++++
 .../security/credential}/JWKCredentialSupport.java |  26 +-
 .../credential/NimbusSecretCredential.java         |   3 +
 ...n.java => ClientSecretCredentialCriterion.java} |  17 +-
 .../BasicClientSecretCredentialFactoryBean.java    |  60 +++
 .../impl/BasicJOSEObjectCredentialResolver.java    |   2 +-
 .../impl/BasicJWKCredentialFactoryBean.java        |   2 +-
 .../ClientSecretCriterionCredentialResolver.java   | 129 +++++++
 .../impl/CriterionCredentialResolver.java          |  69 ----
 .../impl/DataEncryptionAlgorithmCriterion.java     |  82 ++++
 .../impl/KeyManagmentAlgorithmCriterion.java       |  82 ++++
 .../impl/LocalJOSEObjectCredentialResolver.java    |   4 +-
 .../impl/ProviderMetadataCredentialResolver.java   |   2 +
 .../impl/BaseJWTSignatureSecurityHandler.java      |   8 +-
 .../security/impl/BaseSignedJWTTrustEngine.java    |   5 +-
 .../shibboleth/oidc/security/impl/DecryptJWE.java  |   4 +-
 .../oidc/security/impl/EncryptJWTHandler.java      |   1 +
 ...CTokenDecrypter.java => JWETokenDecrypter.java} | 105 +++---
 .../oidc/security/impl/SignJWTHandler.java         |   8 +-
 .../impl/DefaultEncryptionParametersResolver.java  | 420 +++++++++++++--------
 ...lientSecretCriterionCredentialResolverTest.java | 227 +++++++++++
 .../oidc/security/impl/EncryptJWTHandlerTest.java  |   6 +-
 .../impl/ExplicitKeySignedJWTTrustEngineTest.java  |   3 +-
 ...crypterTest.java => JWETokenDecrypterTest.java} | 220 ++++++-----
 .../oidc/security/impl/SignJWTHandlerTest.java     |   6 +-
 .../oidc/security/impl/TestCredentialHelper.java   |  44 +--
 .../DefaultEncryptionParametersResolverTest.java   | 160 ++++----
 .../impl/ClientInformationNodeProcessor.java       |   2 +-
 .../ext/impl/provider/InlineJwksProvider.java      |   2 +-
 .../config/OIDCAuthorizationConfiguration.java     |  16 +-
 .../impl/FormOutboundKeySetResponseMessage.java    |   2 +-
 .../impl/PopulateJWTDecryptionParameters.java      |  13 +-
 .../impl/PopulateJWTEncryptionParameters.java      |  39 +-
 ...pulateJWTSignatureSigningParametersHandler.java |  10 +-
 37 files changed, 1403 insertions(+), 562 deletions(-)

diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CredentialConversionUtil.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/CredentialConversionUtil.java
similarity index 99%
rename from oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CredentialConversionUtil.java
rename to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/CredentialConversionUtil.java
index 24c8859..02608a1 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CredentialConversionUtil.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/CredentialConversionUtil.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.oidc.security.impl;
+package net.shibboleth.oidc.security;
 
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java
index a6f3dcf..b3e5b07 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java
@@ -25,6 +25,7 @@ import com.nimbusds.oauth2.sdk.auth.Secret;
 /**
  * A basic implementation of {@link NimbusSecretCredential}.
  */
+ at Deprecated(since = "2.2.0", forRemoval=true)
 public class BasicNimbusSecretCredential extends AbstractCredential implements NimbusSecretCredential {
 
     /** The client secret. */
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ClientSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ClientSecretCredential.java
new file mode 100644
index 0000000..b7f1c0f
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ClientSecretCredential.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.oidc.security.credential;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.credential.Credential;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEAlgorithm;
+
+/**
+ * Credential wrapping a client_secret. Contains methods to convert the client_secret into suitable keys used for
+ * signing and encryption.
+ * 
+ * <p>Note, despite its name, this is not an opensaml {@link Credential} type.</p>
+ */
+public interface ClientSecretCredential {    
+    
+    /**
+     * Get the client_secret as a UTF-8 encoded String.
+     * 
+     * @return The client_secret.
+     */
+    @Nonnull String getSecret();
+    
+    /**
+     * Get the client_secret as UTF-8 bytes.
+     * 
+     * @return the client_secret in bytes
+     */
+    @Nonnull byte[] getSecretAsBytes();
+    
+    /**
+     * Create a MAC singing key from the client_secret. The MAC key used is the octets of the UTF-8 representation of 
+     * the client_secret value.
+     * 
+     * @return a MAC signing key
+     */
+    @Nonnull JWKCredential toSigningCredential();
+    
+    /**
+     * Create a symmetric encryption key derived from the client_secret and compatible with the key management mode and 
+     * encryption algorithm specified.    
+     * 
+     * @param alg the key management mode
+     * @param enc the encryption algorithm
+     * 
+     * @return a JWKCredential compatible with the 'alg' and 'enc' input
+     * 
+     * @throws JOSEException if a key can not be derived
+     */
+    @Nonnull JWKCredential toEncryptionCredential(@Nonnull final JWEAlgorithm alg, @Nonnull final EncryptionMethod enc)
+            throws JOSEException;
+
+}
\ No newline at end of file
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/DefaultClientSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/DefaultClientSecretCredential.java
new file mode 100644
index 0000000..5d3a560
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/DefaultClientSecretCredential.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.oidc.security.credential;
+
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.opensaml.security.credential.UsageType;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.util.StandardCharset;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * A basic implementation of {@link ClientSecretCredential}.
+ */
+ at ThreadSafe
+public class DefaultClientSecretCredential implements ClientSecretCredential {
+    
+    /** Default client_secret keyname.*/
+    @Nonnull private static final String DEFAULT_SECRET_KEY_NAME = "client_secret_credential";
+
+    /** The client_secret. */
+    @Nonnull private final byte[] clientSecret;
+    
+    /** The chosen client_secret keyname.*/
+    @Nonnull @NotEmpty private final String secretKeyName;
+    
+    /**
+     * 
+     * Constructor.
+     *
+     * @param secret the client_secret
+     */
+    public DefaultClientSecretCredential(@Nonnull final String secret) {
+        Constraint.isNotEmpty(secret, "Secret can not be null or empty");
+        clientSecret = secret.getBytes(StandardCharset.UTF_8);
+        secretKeyName = DEFAULT_SECRET_KEY_NAME;
+    }
+    
+    /**
+     * 
+     * Constructor.
+     *
+     * @param secret the client_secret
+     * @param keyName the keyname to use when creating a {@link JWKCredential}
+     */
+    public DefaultClientSecretCredential(@Nonnull final String secret, @Nonnull final String keyName) {
+        Constraint.isNotEmpty(secret, "Secret can not be null or empty");
+        clientSecret = secret.getBytes(StandardCharset.UTF_8);
+        secretKeyName = Constraint.isNotEmpty(keyName, "Secret keyname can not be null or empty");
+    }
+    
+    @Override
+    @Nonnull public String getSecret() {
+        return new String(clientSecret, StandardCharsets.UTF_8);
+    }
+    
+    @Override
+    @NotLive @Nonnull public byte[] getSecretAsBytes(){
+        return clientSecret.clone();
+    }
+
+    @Override
+    @Nonnull public JWKCredential toSigningCredential() {
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();  
+        jwkCredential.getKeyNames().add(secretKeyName);
+        jwkCredential.setKid(secretKeyName);
+        jwkCredential.setSecretKey(new SecretKeySpec(getSecretAsBytes(), "NONE"));
+        jwkCredential.setUsageType(UsageType.SIGNING);        
+        return jwkCredential;
+    }
+
+    @Override
+    public JWKCredential toEncryptionCredential(final JWEAlgorithm alg, final EncryptionMethod enc) 
+                throws JOSEException {
+        // Derive key using the algorithm and enc method
+        final SecretKey key = JWKCredentialSupport.generateSymmetricKey(clientSecret, alg, enc);
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential(); 
+        jwkCredential.getKeyNames().add(secretKeyName); 
+        jwkCredential.setKid(secretKeyName);
+        jwkCredential.setUsageType(UsageType.ENCRYPTION); 
+        jwkCredential.setSecretKey(key);
+        return  jwkCredential;
+    }
+    
+}
\ No newline at end of file
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKCredentialSupport.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/JWKCredentialSupport.java
similarity index 81%
rename from oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKCredentialSupport.java
rename to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/JWKCredentialSupport.java
index faefa2c..ba7d702 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKCredentialSupport.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/JWKCredentialSupport.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.oidc.security.credential.impl;
+package net.shibboleth.oidc.security.credential;
 
 import javax.annotation.Nullable;
 import javax.crypto.SecretKey;
@@ -27,8 +27,8 @@ import com.nimbusds.jose.util.StandardCharset;
 import com.nimbusds.oauth2.sdk.auth.Secret;
 import com.nimbusds.oauth2.sdk.jose.SecretKeyDerivation;
 
-import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
+
 
 /** Provide JWK specific credential support.*/
 public final class JWKCredentialSupport {
@@ -60,8 +60,7 @@ public final class JWKCredentialSupport {
         //build a new credential so the old is left in its original state
         return CredentialConversionUtil.copySymmetricCredentialWithNewSecret(
                 credential, "derived-"+CredentialConversionUtil.resolveKid(credential), derivedKey);
-    }
-   
+    } 
     
     /**
      * Generate symmetric key from client_secret using the algorithms supplied.
@@ -80,5 +79,22 @@ public final class JWKCredentialSupport {
         return SecretKeyDerivation.deriveSecretKey(
                 new Secret(new String(clientSecret, StandardCharset.UTF_8)), alg, enc);        
     }
+    
+    /**
+     * Generate symmetric key from client_secret using the algorithms supplied.
+     * 
+     * @param clientSecret client secret to derive a key from
+     * @param alg the key management mode or key transport algorithm
+     * @param enc the content encryption algorithm
+     * 
+     * @return key derived from client secret.
+
+     * @throws JOSEException on error 
+     */
+    public static final SecretKey generateSymmetricKey(final Secret clientSecret, final JWEAlgorithm alg,
+            final EncryptionMethod enc) throws JOSEException {
+        
+        return SecretKeyDerivation.deriveSecretKey(clientSecret, alg, enc);        
+    }
 
 }
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java
index b91627d..24a72c3 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java
@@ -25,7 +25,10 @@ import com.nimbusds.oauth2.sdk.auth.Secret;
 
 /**
  * Credential wrapping {@link Secret}.
+ * 
+ * @deprecated use {@link ClientSecretCredential}
  */
+ at Deprecated
 public interface NimbusSecretCredential extends Credential {
     
     /**
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/StaticCredentialCriterion.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/ClientSecretCredentialCriterion.java
similarity index 78%
rename from oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/StaticCredentialCriterion.java
rename to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/ClientSecretCredentialCriterion.java
index d83982c..e537c5a 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/StaticCredentialCriterion.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/ClientSecretCredentialCriterion.java
@@ -19,8 +19,7 @@ package net.shibboleth.oidc.security.jose.criterion;
 
 import javax.annotation.Nonnull;
 
-import org.opensaml.security.credential.Credential;
-
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.resolver.Criterion;
 
@@ -29,10 +28,10 @@ import net.shibboleth.utilities.java.support.resolver.Criterion;
  * 
  * @since 2.2.0
  */
-public class StaticCredentialCriterion implements Criterion {
+public class ClientSecretCredentialCriterion implements Criterion {
     
     /** The credential to hold.*/
-    @Nonnull private final Credential credential;
+    @Nonnull private final ClientSecretCredential credential;
     
     /**
      * 
@@ -40,7 +39,7 @@ public class StaticCredentialCriterion implements Criterion {
      *
      * @param cred the credential to hold.
      */
-    public StaticCredentialCriterion(@Nonnull final Credential cred) {
+    public ClientSecretCredentialCriterion(@Nonnull final ClientSecretCredential cred) {
         credential = Constraint.isNotNull(cred, "Credential can not be null");
     }
     
@@ -49,7 +48,7 @@ public class StaticCredentialCriterion implements Criterion {
      * 
      * @return the credential
      */
-    @Nonnull public Credential getCredential() {
+    @Nonnull public ClientSecretCredential getCredential() {
         return credential;
     }
     
@@ -57,7 +56,7 @@ public class StaticCredentialCriterion implements Criterion {
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append("StaticCredentialCriterion [credential=");
+        builder.append("ClientSecretCredentialCriterion [credential=");
         builder.append(credential);
         builder.append("]");
         return builder.toString();
@@ -80,8 +79,8 @@ public class StaticCredentialCriterion implements Criterion {
             return false;
         }
 
-        if (obj instanceof StaticCredentialCriterion) {
-            return credential.equals(((StaticCredentialCriterion) obj).credential);
+        if (obj instanceof ClientSecretCredentialCriterion) {
+            return credential.equals(((ClientSecretCredentialCriterion) obj).credential);
         }
 
         return false;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicClientSecretCredentialFactoryBean.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicClientSecretCredentialFactoryBean.java
new file mode 100644
index 0000000..46bd2d6
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicClientSecretCredentialFactoryBean.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.oidc.security.credential.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.ext.spring.factory.AbstractComponentAwareFactoryBean;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Factory to generate a {@link ClientSecretCredential} from a client_secret string.
+ */
+public class BasicClientSecretCredentialFactoryBean 
+                    extends AbstractComponentAwareFactoryBean<DefaultClientSecretCredential> {
+    
+    /** The secret to use when creating a BasicJWKCredential.*/
+    @Nullable private String secret;
+    
+    /** 
+     * Set the secret to use. 
+     * 
+     * @param secretIn the secret
+     */
+    public void setSecret(@Nonnull @NotEmpty final String secretIn) {
+        secret = Constraint.isNotEmpty(secretIn, "Secret can not be null or empty");
+    }
+
+    @Override
+    protected DefaultClientSecretCredential doCreateInstance() throws Exception {
+        if (secret == null) {
+            throw new Exception("Nimbus secret can not be null");
+        }
+        return new DefaultClientSecretCredential(secret);      
+    }
+
+    @Override
+    public Class<?> getObjectType() {
+        return DefaultClientSecretCredential.class;
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java
index 2426844..f409a9c 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java
@@ -41,9 +41,9 @@ import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jose.jwk.KeyType;
 import com.nimbusds.jose.jwk.RSAKey;
 
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
 import net.shibboleth.oidc.security.jose.criterion.JOSEObjectCriterion;
 import net.shibboleth.oidc.security.jose.criterion.KeyIdCriterion;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java
index da46e52..d59a0ac 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java
@@ -38,8 +38,8 @@ import com.nimbusds.jose.jwk.KeyType;
 import com.nimbusds.jose.jwk.OctetSequenceKey;
 
 import net.shibboleth.idp.profile.spring.factory.AbstractCredentialFactoryBean;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolver.java
new file mode 100644
index 0000000..9d5dd84
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolver.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.oidc.security.credential.impl;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEAlgorithm;
+
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/**
+ * Extracts a credential held inside the {@link ClientSecretCredentialCriterion} from the given criteria set.
+ * Supports credential filter via evaluable criterion.
+ * 
+ * <p>Only supports symmetric key algorithms. Request for assymetric key algorithms are ignored.</p>
+ * 
+ * <p>A different key credential is derived for different usage types. MAC ('signing') keys are generated directly off 
+ * the UTF-8 octets of the client_secret. Encryption/Decryption keys are generated specifically for the key management 
+ * mode and encryption algorithm pulled out of the criteria set —and as such, if these criteria do not exist, resolution 
+ * for encryption keys will fail.</p>   
+ */
+public class ClientSecretCriterionCredentialResolver extends BasicJOSEObjectCredentialResolver {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ClientSecretCriterionCredentialResolver.class);
+    
+    /** The pre-determined usage type of the credential that is returned from the client_secret.*/
+    @Nonnull private final UsageType forUsageType;
+    
+    /**
+     * 
+     * Constructor.
+     *
+     * @param usage the usage type of the returned credential
+     */
+    public ClientSecretCriterionCredentialResolver(@Nonnull @ParameterName(name="usage") final UsageType usage) {
+        forUsageType = Constraint.isNotNull(usage, "Usage can not be null");
+    }
+    
+    @Override
+    @Nonnull protected Iterable<Credential> resolveFromSource(@Nonnull final CriteriaSet criteriaSet) 
+            throws ResolverException {        
+        Constraint.isNotNull(criteriaSet, "CriteriaSet was null");       
+        
+        if (criteriaSet.contains(ClientSecretCredentialCriterion.class)) {
+            final ClientSecretCredentialCriterion credentialCriterion = criteriaSet.get(ClientSecretCredentialCriterion.class);
+            final ClientSecretCredential secretCred = credentialCriterion.getCredential();   
+            log.debug("Found client secret credential");           
+            if (forUsageType == UsageType.SIGNING) {
+                // Create a signing credential
+                final Credential signingCred = secretCred.toSigningCredential();
+                log.debug("Derived signing credential '{}'", signingCred.getKeyNames());
+                
+                return List.of(signingCred);
+                
+            } else if (forUsageType == UsageType.ENCRYPTION) {
+                // Create an encryption credential suitable for the algorithms specified
+                final KeyManagmentAlgorithmCriterion alg = criteriaSet.get(KeyManagmentAlgorithmCriterion.class);
+                if (alg == null) {
+                    throw new ResolverException(
+                            "Credential criteria set did not contain an instance of KeyManagmentAlgorithmCriterion");
+                }
+                // Technically the encryption method is only relevant to key derivation for the Direct Encryption mode
+                final DataEncryptionAlgorithmCriterion enc = criteriaSet.get(DataEncryptionAlgorithmCriterion.class);
+                if (enc == null) {
+                    throw new ResolverException(
+                            "Credential criteria set did not contain an instance of DataEncryptionAlgorithmCriterion");
+                }
+                
+                // Can only derive symmetric key credentials, ignore if not
+                if (JWEAlgorithm.Family.SYMMETRIC.contains(JWEAlgorithm.parse(alg.getAlgorithm()))) {                     
+                    try {
+                        final Credential derivedCred = secretCred.toEncryptionCredential(JWEAlgorithm.parse(alg.getAlgorithm()), 
+                                EncryptionMethod.parse(enc.getEncAlgorithm()));
+                        
+                        log.debug("Derived encryption credential '{}' from 'alg={}' and 'enc={}'", derivedCred.getKeyNames()
+                                ,alg.getAlgorithm(), enc.getEncAlgorithm());
+                        return List.of(derivedCred);
+                        
+                    } catch (final JOSEException e) {
+                        log.warn("Unable to derive symmetric encryption key from client_secret using 'alg={}' and 'enc={}'", 
+                                alg.getAlgorithm(), enc.getEncAlgorithm());                    
+                    }
+                    throw new ResolverException("Unable to create encryption key from client_secret");
+                } else {
+                    log.trace("Asymmetric key requested, client_secret not appropriate");
+                    return Collections.emptyList();
+                }
+            } else {
+                throw new ResolverException("Unable to create key from client_secret, incompatible usage type");
+            }
+        } else {
+            log.debug("Criteria did not contain a StaticClientSecretCredentialCriterion");
+            return Collections.emptyList();
+        }
+    }
+    
+    
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/CriterionCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/CriterionCredentialResolver.java
deleted file mode 100644
index 160513f..0000000
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/CriterionCredentialResolver.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.oidc.security.credential.impl;
-
-import java.util.Collections;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.security.credential.Credential;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-import net.shibboleth.utilities.java.support.resolver.ResolverException;
-
-/**
- * Extracts a credential held inside the {@link StaticCredentialCriterion} from the given criteria set.
- * Supports credential filter via evaluable criterion.
- */
-public class CriterionCredentialResolver extends BasicJOSEObjectCredentialResolver {
-    
-    /** Class logger. */
-    @Nonnull private final Logger log = LoggerFactory.getLogger(CriterionCredentialResolver.class);
-    
-    @Override
-    @Nonnull protected Iterable<Credential> resolveFromSource(@Nonnull final CriteriaSet criteriaSet) 
-            throws ResolverException {        
-        Constraint.isNotNull(criteriaSet, "CriteriaSet was null");       
-        
-        if (criteriaSet.contains(StaticCredentialCriterion.class)) {
-            final StaticCredentialCriterion credentialCriterion = criteriaSet.get(StaticCredentialCriterion.class);
-            final Credential credential = credentialCriterion.getCredential();      
-            if (credential instanceof JWKCredential && log.isDebugEnabled()) {
-                log.debug("Found credential '{}' with usage '{}' and alg '{}' from criterion", 
-                        CredentialConversionUtil.resolveKid(credential),
-                        credential.getUsageType(), ((JWKCredential)credential).getAlgorithm());
-            } else {
-                log.debug("Found credential '{}' with usage '{}' from criterion", 
-                        credential.getKeyNames(), credential.getUsageType());
-            }
-            return List.of(credential);               
-            
-        } else {
-            log.trace("Criteria did not contain a StaticCredentialCriterion");
-            return Collections.emptyList();
-        }
-    }
-    
-}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/DataEncryptionAlgorithmCriterion.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/DataEncryptionAlgorithmCriterion.java
new file mode 100644
index 0000000..c925fc9
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/DataEncryptionAlgorithmCriterion.java
@@ -0,0 +1,82 @@
+
+package net.shibboleth.oidc.security.credential.impl;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.Criterion;
+
+/**
+ * An implementation of {@link Criterion} which specifies content encryption algorithm criteria.
+ */
+public final class DataEncryptionAlgorithmCriterion implements Criterion {
+    
+    /** Key algorithm type of resolved credentials. */
+    private String encAlgorithm;
+    
+    /**
+     * Constructor.
+     *
+     * @param algorithm key algorithm
+     */
+    public DataEncryptionAlgorithmCriterion(@Nonnull final String algorithm) {
+        setEncAlgorithm(algorithm);
+    }
+ 
+    /**
+     * Get the encryption algorithm criteria.
+     * 
+     * @return returns the keyAlgorithm.
+     */
+    @Nonnull public String getEncAlgorithm() {
+        return encAlgorithm;
+    }
+
+    /**
+     * Set the encryption algorithm criteria.
+     * 
+     * @param algorithm The encryption algorithm to set.
+     */
+    public void setEncAlgorithm(@Nonnull final String algorithm) {
+        final String trimmed = StringSupport.trimOrNull(algorithm);
+        Constraint.isNotNull(trimmed, "Encryption algorithm criteria cannot be null or empty");
+
+        encAlgorithm = trimmed;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("DataEncryptionAlgorithmCriterion [encAlgorithm=");
+        builder.append(encAlgorithm);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return encAlgorithm.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof DataEncryptionAlgorithmCriterion) {
+            return encAlgorithm.equals(((DataEncryptionAlgorithmCriterion) obj).encAlgorithm);
+        }
+
+        return false;
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/KeyManagmentAlgorithmCriterion.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/KeyManagmentAlgorithmCriterion.java
new file mode 100644
index 0000000..46724ed
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/KeyManagmentAlgorithmCriterion.java
@@ -0,0 +1,82 @@
+
+package net.shibboleth.oidc.security.credential.impl;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.Criterion;
+
+/**
+ * An implementation of {@link Criterion} which specifies content encryption algorithm criteria.
+ */
+public final class KeyManagmentAlgorithmCriterion implements Criterion {
+    
+    /** Key algorithm type of resolved credentials. */
+    private String algorithmName;
+    
+    /**
+     * Constructor.
+     *
+     * @param algorithm key algorithm
+     */
+    public KeyManagmentAlgorithmCriterion(@Nonnull final String algorithm) {
+        setAlgorithm(algorithm);
+    }
+ 
+    /**
+     * Get the algorithm criteria.
+     * 
+     * @return returns the keyAlgorithm.
+     */
+    @Nonnull public String getAlgorithm() {
+        return algorithmName;
+    }
+
+    /**
+     * Set the algorithm criteria.
+     * 
+     * @param algorithm The encryption algorithm to set.
+     */
+    public void setAlgorithm(@Nonnull final String algorithm) {
+        final String trimmed = StringSupport.trimOrNull(algorithm);
+        Constraint.isNotNull(trimmed, "Key Management algorithm criteria cannot be null or empty");
+
+        algorithmName = trimmed;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("KeyManagmentAlgorithmCriterion [algorithm=");
+        builder.append(algorithmName);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return algorithmName.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof KeyManagmentAlgorithmCriterion) {
+            return algorithmName.equals(((KeyManagmentAlgorithmCriterion) obj).algorithmName);
+        }
+
+        return false;
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
index 5446ac0..53eadd8 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
@@ -37,7 +37,7 @@ import com.nimbusds.jose.JWEHeader;
 import com.nimbusds.jose.JWSHeader;
 
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
-import net.shibboleth.oidc.security.impl.OIDCTokenDecrypter;
+import net.shibboleth.oidc.security.impl.JWETokenDecrypter;
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
 import net.shibboleth.utilities.java.support.annotation.constraint.Live;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
@@ -58,7 +58,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
  * 
  * <p>
  * A typical use case for this class would be as a resolver of decryption keys,
- * such as is needed by {@link OIDCTokenDecrypter}}.
+ * such as is needed by {@link JWETokenDecrypter}}.
  * </p>
  * 
  * <p>
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java
index 586a621..f633c8c 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java
@@ -135,6 +135,8 @@ public class ProviderMetadataCredentialResolver extends BasicJOSEObjectCredentia
     @Nonnull protected Collection<Credential> resolveFromMetadata(@Nonnull final CriteriaSet criteriaSet, 
             @Nonnull final OIDCProviderMetadata metadata) {
         
+        log.debug("Resolving JWKs from provider metadata");
+        
         final LinkedHashSet<Credential> credentials = new LinkedHashSet<>(1);
         
         if (metadata.getJWKSetURI() != null) {            
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
index 789f88b..3e1c0de 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
@@ -27,7 +27,6 @@ import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.opensaml.messaging.handler.MessageHandlerException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.context.navigate.ParentProfileRequestContextLookup;
-import org.opensaml.security.credential.Credential;
 import org.opensaml.security.credential.UsageType;
 import org.opensaml.security.criteria.UsageCriterion;
 import org.opensaml.security.messaging.impl.BaseTrustEngineSecurityHandler;
@@ -41,10 +40,11 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
 
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
 import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
 import net.shibboleth.oidc.security.jose.criterion.ProviderMetadataCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.logic.FunctionSupport;
@@ -178,9 +178,9 @@ public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSec
         }
 
         if (profileConfiguration != null) {
-            final Credential credential = profileConfiguration.getClientCredential(PRC_LOOKUP.apply(messageContext));
+            final ClientSecretCredential credential = profileConfiguration.getClientCredential(PRC_LOOKUP.apply(messageContext));
             if (credential != null) {
-                criteriaSet.add(new StaticCredentialCriterion(credential));
+                criteriaSet.add(new ClientSecretCredentialCriterion(credential));
             } else {
                 log.trace("{} No credential found from the profile configuration", getLogPrefix());
             }
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java
index f5dcc59..0d0c798 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java
@@ -172,9 +172,8 @@ public abstract class BaseSignedJWTTrustEngine<TrustBasisType> implements TrustE
                 if (log.isDebugEnabled()) {
                     final String kid = credential instanceof JWKCredential ?
                             ((JWKCredential) credential).getKid() : null;
-                    log.debug("JWT {} verified using algorithm {}{}", signedJWT.serialize(),
-                            algorithm.getName(), 
-                            kid != null ? " and key " + kid : "");
+                    log.debug("Verified JWT using algorithm {}{}: {} ", algorithm.getName(), 
+                            kid != null ? " and key " + kid : "", signedJWT.serialize());
                 }
                 log.debug("Signature validation using candidate credential was successful");
                 return true;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java
index 86d0ee3..920c48c 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java
@@ -70,7 +70,7 @@ public class DecryptJWE extends AbstractProfileAction {
     @Nullable private EncryptedJWT encryptedJwt;
     
     /** The decryption object. */
-    @Nullable private OIDCTokenDecrypter decrypter;
+    @Nullable private JWETokenDecrypter decrypter;
     
     /** Strategy used to locate the {@link SecurityParametersContext}. */
     @Nonnull private Function<ProfileRequestContext, SecurityParametersContext> securityParamsLookupStrategy;
@@ -155,7 +155,7 @@ public class DecryptJWE extends AbstractProfileAction {
             return false;
         } else {
             final DecryptionParameters params = paramsCtx.getDecryptionParameters();
-            decrypter = new OIDCTokenDecrypter(params);
+            decrypter = new JWETokenDecrypter(params);
         }
         
         
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java
index bc56e93..7a2afb4 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java
@@ -47,6 +47,7 @@ import com.nimbusds.jose.crypto.RSAEncrypter;
 import com.nimbusds.jwt.EncryptedJWT;
 import com.nimbusds.jwt.JWT;
 
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.jose.EncryptionParameters;
 import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypter.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWETokenDecrypter.java
similarity index 88%
rename from oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypter.java
rename to oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWETokenDecrypter.java
index cc5ad63..9eb48bc 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypter.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWETokenDecrypter.java
@@ -65,9 +65,11 @@ import com.nimbusds.jwt.EncryptedJWT;
 import com.nimbusds.jwt.JWT;
 import com.nimbusds.jwt.JWTParser;
 
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.credential.JWKCredential;
+import net.shibboleth.oidc.security.credential.impl.DataEncryptionAlgorithmCriterion;
 import net.shibboleth.oidc.security.credential.impl.EvaluableKeyIDCredentialCriterion;
-import net.shibboleth.oidc.security.credential.impl.JWKCredentialSupport;
+import net.shibboleth.oidc.security.credential.impl.KeyManagmentAlgorithmCriterion;
 import net.shibboleth.oidc.security.jose.DecryptionParameters;
 import net.shibboleth.oidc.security.jose.criterion.JOSEObjectCriterion;
 import net.shibboleth.oidc.security.jose.criterion.KeyIdCriterion;
@@ -82,17 +84,14 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
  * The {@link EncryptedJWT} will be decrypted in-place, with its {@link State} changing to {@link State#DECRYPTED}
  * on successful decryption. Any error that occurs decrypting the JWT will throw an {@link DecryptionException}.
  * 
- * <p>As this decrypter is specific to OIDC then, as per OIDC specification, symmetric decryption keys are derived from 
- * resolved symmetric keys (e.g. a client_secret).</p>
- * 
  * <p>A decrypter should be created for each new decryption operation.</p>
  * 
  * @since 2.2.0
  */
-public class OIDCTokenDecrypter {
+public class JWETokenDecrypter {
 
     /** Class logger. */
-    private final Logger log = LoggerFactory.getLogger(OIDCTokenDecrypter.class);
+    private final Logger log = LoggerFactory.getLogger(JWETokenDecrypter.class);
 
     /** The JWT decryption parameters. */
     private final DecryptionParameters params;
@@ -103,7 +102,7 @@ public class OIDCTokenDecrypter {
      *
      * @param decryptionParams the parameters to use during decryption
      */
-    public OIDCTokenDecrypter(@Nonnull final DecryptionParameters decryptionParams) {
+    public JWETokenDecrypter(@Nonnull final DecryptionParameters decryptionParams) {
         params = Constraint.isNotNull(decryptionParams, "Decryption params can not be null");
     }
 
@@ -148,7 +147,7 @@ public class OIDCTokenDecrypter {
                 throw new DecryptionException("Error decrypting JWT", e);
             }
         } else {
-            // Should not happen if all the above key managment modes are correctly captured
+            // Should not happen if all the above key management modes are correctly captured
             throw new DecryptionException("JWE failed to decrypt without error");
         }  
 
@@ -157,7 +156,7 @@ public class OIDCTokenDecrypter {
     
     /**
      * Build a criteria set using the additional criteria in the params, those supplied, and those
-     * that relating to the encrypted JWT.
+     * that relate to the encrypted JWT.
      * 
      * @param encryptedObject the encrypted JWT to build criterion from
      * @param criteria criteria supplied, can be {@literal null}.
@@ -184,6 +183,17 @@ public class OIDCTokenDecrypter {
                     new KeyIdCriterion(keyId)));
         }
         
+        // Add algorithm if present(should be)
+        if (encryptedObject.getHeader().getAlgorithm() != null) {
+            newCriteriaSet.add(
+                    new KeyManagmentAlgorithmCriterion(encryptedObject.getHeader().getAlgorithm().getName()));
+        }
+        // Add encryption method if present(should be)
+        if (encryptedObject.getHeader().getEncryptionMethod() != null) {
+            newCriteriaSet.add(
+                    new DataEncryptionAlgorithmCriterion(encryptedObject.getHeader().getEncryptionMethod().getName()));
+        }
+        
         // Add the entire object so the resolver can access it
         newCriteriaSet.add(new JOSEObjectCriterion(encryptedObject));
 
@@ -215,7 +225,7 @@ public class OIDCTokenDecrypter {
         final KeyAlgorithmCriterion algoCrit = buildKeyAlgorithmCriteria(algAlgorithmURI);        
         if (algoCrit != null) {
             criteriaSet.add(algoCrit);
-            log.debug("Added decryption key algorithm  'alg' criteria: {}", algoCrit.getKeyAlgorithm());
+            log.debug("Added decryption key algorithm ('alg') criteria: {}", algoCrit.getKeyAlgorithm());
         }
         
         // Add key size criteria if possible
@@ -315,11 +325,12 @@ public class OIDCTokenDecrypter {
      * <p>For each credential, algorithm compatibly is checked against that described by the JWE and any
      * includes and excludes lists configured.</p>
      * 
-     * <p>The process terminates when a resolved credential decrypts the JWT.</p>
+     * <p>The process terminates when a resolved credential decrypts the JWT. The resolvers should only retrieve
+     * appropriate keys, but that is not guaranteed.</p>
      * 
      * @param encryptedObject the encrypted JWT to decrypt - in place.
      * 
-     * @throws DecryptionException if the resolved credentials could not be used to decrypt the JWT.
+     * @throws DecryptionException if any of the resolved credentials could not be used to decrypt the JWT.
      */
     private void decryptUsingKeyAgreement(final EncryptedJWT encryptedObject) throws DecryptionException {
   
@@ -334,8 +345,16 @@ public class OIDCTokenDecrypter {
         
         try {
             for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) {
+                if (!(cred instanceof JWKCredential)) {
+                    if (log.isTraceEnabled()) {
+                        log.trace("JWT decryption requires a JWK credential, resolved credential '{}' was not", 
+                                CredentialConversionUtil.resolveKid(cred));
+                    }
+                    // Require a JWKCredential
+                    continue;
+                }
                 try {
-                    validateKeyManagmentAlgorithm(encryptedObject, cred);
+                    validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
                     final JWEDecrypter decrypter = new ECDHDecrypter((ECPrivateKey)cred.getPrivateKey());
                     encryptedObject.decrypt(decrypter);
                     return;
@@ -352,14 +371,15 @@ public class OIDCTokenDecrypter {
     }
 
     /**
-     * Decrypt the encrypted JWT by first decrypting the wrapped content encryption key using on of the shared 
+     * Decrypt the encrypted JWT by first decrypting the wrapped content encryption key using one of the shared 
      * key wrapping keys derived from a symmetric key resolved by the 
      * {@link DecryptionParameters#getKEKCredentialResolver()} resolver. 
      * 
      * <p>For each credential, algorithm compatibly is checked against that described by the JWE and any
      * includes and excludes lists configured.</p>
      * 
-     * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.</p>
+     * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.
+     * The resolvers should only retrieve appropriate keys, but that is not guaranteed.</p>
      * 
      * @param encryptedObject the encrypted JWT to decrypt - in place.
      * 
@@ -387,13 +407,9 @@ public class OIDCTokenDecrypter {
                     continue;
                 }
                 try {
-                    final JWEAlgorithm alg = validateKeyManagmentAlgorithm(encryptedObject, cred);
-                    final EncryptionMethod enc = validateContentEncryptionAlgorithm(encryptedObject, cred);
-                    //Key wrapping requires a derived credential
-                    final JWKCredential derivedKey = 
-                            JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc((JWKCredential)cred, 
-                                    alg, enc);
-                    final JWEDecrypter decrypter = new AESDecrypter(derivedKey.getSecretKey());
+                    validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
+                    validateContentEncryptionAlgorithm(encryptedObject,(JWKCredential) cred);
+                    final JWEDecrypter decrypter = new AESDecrypter(cred.getSecretKey());
                     encryptedObject.decrypt(decrypter);
                     return;
                 } catch (final JOSEException | DecryptionException e) {
@@ -416,7 +432,8 @@ public class OIDCTokenDecrypter {
      * <p>For each credential, algorithm compatibly is checked against that described by the JWE and any
      * includes and excludes lists configured.</p>
      * 
-     * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.</p>
+     * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.
+     * The resolvers should only retrieve appropriate keys, but that is not guaranteed.</p>
      * 
      * @param encryptedObject the encrypted JWT to decrypt - in place.
      * 
@@ -435,8 +452,16 @@ public class OIDCTokenDecrypter {
         
         try {
             for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) { 
+                if (!(cred instanceof JWKCredential)) {
+                    if (log.isTraceEnabled()) {
+                        log.trace("JWT decryption requires a JWK credential, resolved credential '{}' was not", 
+                                CredentialConversionUtil.resolveKid(cred));
+                    }
+                    // Require a JWKCredential
+                    continue;
+                }
                 try {
-                    validateKeyManagmentAlgorithm(encryptedObject, cred);
+                    validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
                     final JWEDecrypter decrypter = new RSADecrypter(cred.getPrivateKey());
                     encryptedObject.decrypt(decrypter);
                     return;
@@ -461,7 +486,7 @@ public class OIDCTokenDecrypter {
      * includes and excludes lists configured.</p>
      * 
      * <p>The first resolved (and derived) credential that decrypts the JWT produces a result, 
-     * and the process terminates.</p>
+     * and the process terminates. The resolvers should only retrieve appropriate keys, but that is not guaranteed.</p>
      * 
      * @param encryptedObject the encrypted JWT to decrypt - in place.
      * 
@@ -485,20 +510,16 @@ public class OIDCTokenDecrypter {
             for (final Credential cred : params.getContentEncryptionKeyCredentialResolver().resolve(criteria)) {
                 if (!(cred instanceof JWKCredential)) {
                     if (log.isTraceEnabled()) {
-                        log.trace("JWT direct decryption requires a JWK credential, resolved credential "
-                                + "'{}' was not", CredentialConversionUtil.resolveKid(cred));
+                        log.trace("JWT decryption requires a JWK credential, resolved credential '{}' was not", 
+                                CredentialConversionUtil.resolveKid(cred));
                     }
                     // Require a JWKCredential
                     continue;
                 }
                 try {
-                    validateKeyManagmentAlgorithm(encryptedObject, cred);
-                    final EncryptionMethod enc = validateContentEncryptionAlgorithm(encryptedObject, cred);
-                    // Symmetric key to use is derived from shared symmetric key e.g. client_secret
-                    final JWKCredential derivedKey = 
-                            JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc((JWKCredential)cred, 
-                                    JWEAlgorithm.DIR, enc);
-                    final JWEDecrypter decrypter = new DirectDecrypter(derivedKey.getSecretKey());
+                    validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
+                    validateContentEncryptionAlgorithm(encryptedObject, (JWKCredential)cred);
+                    final JWEDecrypter decrypter = new DirectDecrypter(cred.getSecretKey());
                     encryptedObject.decrypt(decrypter);
                     return;
                 } catch (final JOSEException | DecryptionException e) {
@@ -527,7 +548,7 @@ public class OIDCTokenDecrypter {
      */
  // Checkstyle: CyclomaticComplexity OFF
     private JWEAlgorithm validateKeyManagmentAlgorithm(
-            @Nonnull final EncryptedJWT encryptedObject, @Nonnull final Credential cred) throws DecryptionException {
+            @Nonnull final EncryptedJWT encryptedObject, @Nonnull final JWKCredential cred) throws DecryptionException {
         
         if (encryptedObject.getHeader() == null) {
             throw new DecryptionException("JWE did not contain a JOSE header, is in an illegal state");
@@ -536,10 +557,9 @@ public class OIDCTokenDecrypter {
         final JWEAlgorithm headerAlg = encryptedObject.getHeader().getAlgorithm();
         validateAlgorithmURI(headerAlg.getName());
 
-        if (cred instanceof JWKCredential && ((JWKCredential)cred).getAlgorithm() != null) {
-            final JWKCredential jwkCred = (JWKCredential)cred;
-            if (!headerAlg.equals(jwkCred.getAlgorithm())) {
-                throw new DecryptionException("Credential algorithm '"+jwkCred.getAlgorithm()+"' "
+        if (cred.getAlgorithm() != null) {
+            if (!headerAlg.equals(cred.getAlgorithm())) {
+                throw new DecryptionException("Credential algorithm '"+cred.getAlgorithm()+"' "
                         + "was not a match for the "
                         + "algorithm '"+encryptedObject.getHeader().getAlgorithm()+"'");
                              
@@ -557,7 +577,7 @@ public class OIDCTokenDecrypter {
             throw new DecryptionException("Credential did not contain an AES secret key");
         }
         if (JWEAlgorithm.DIR.equals(headerAlg) && cred.getSecretKey() == null) {
-            throw new DecryptionException("Credential did not contain an direct encryption secret key");
+            throw new DecryptionException("Credential did not contain a direct encryption secret key");
         }
         
         //All fine    
@@ -578,7 +598,7 @@ public class OIDCTokenDecrypter {
      * @throws DecryptionException if there is an algorithm mismatch.
      */
     @Nonnull private EncryptionMethod validateContentEncryptionAlgorithm(
-            @Nonnull final EncryptedJWT encryptedObject, @Nonnull final Credential cred) throws DecryptionException {
+            @Nonnull final EncryptedJWT encryptedObject, @Nonnull final JWKCredential cred) throws DecryptionException {
         
         if (encryptedObject.getHeader() == null) {
             throw new DecryptionException("JWE did not contain a JOSE header, is in an illegal state");
@@ -589,8 +609,7 @@ public class OIDCTokenDecrypter {
             throw new DecryptionException("JWE did not contain an 'enc' JOSE header, is in an illegal state");
         }
             
-        final String encAlgorithmURI = StringSupport.trimOrNull(enc.getName());
-        
+        final String encAlgorithmURI = StringSupport.trimOrNull(enc.getName());        
         validateAlgorithmURI(encAlgorithmURI);
         
         final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(encAlgorithmURI);
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java
index 98e9b96..2175400 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java
@@ -46,6 +46,7 @@ import com.nimbusds.jwt.JWT;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.SignedJWT;
 
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.credential.JWKCredential;
 import net.shibboleth.oidc.security.jose.SignatureSigningParameters;
 import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
@@ -59,7 +60,6 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
 /**
  * Action that signs a request object and sets it as the request object to the authentication request.
  */
-//TODO move to commons?
 public class SignJWTHandler extends AbstractMessageHandler {
     
     /** Class logger. */
@@ -216,9 +216,11 @@ public class SignJWTHandler extends AbstractMessageHandler {
             jwt = new SignedJWT(headerBuilder.build(), jwtClaimSetToSign);
             jwt.sign(signer);
             if (log.isDebugEnabled() && !log.isTraceEnabled()) {
-                log.debug("{} Signed JWT '{}'", getLogPrefix(), logName);
+                log.debug("{} Signed JWT '{}' using kid '{}'", getLogPrefix(), logName, 
+                        CredentialConversionUtil.resolveKid(credential));
             } else if (log.isTraceEnabled()) {
-                log.trace("{} Signed JWT '{}': {}", getLogPrefix(), logName, jwt.serialize());
+                log.trace("{} Signed JWT '{}' using kid '{}': {}", getLogPrefix(), logName, 
+                        CredentialConversionUtil.resolveKid(credential),jwt.serialize());
             }            
             
             if (jwt.getState() != State.SIGNED) {
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java
index 0cc7512..7cbb806 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java
@@ -33,7 +33,8 @@ import org.opensaml.security.credential.Credential;
 import org.opensaml.security.credential.CredentialResolver;
 import org.opensaml.security.credential.CredentialSupport;
 import org.opensaml.security.credential.UsageType;
-import org.opensaml.security.credential.criteria.impl.EvaluableUsageCredentialCriterion;
+import org.opensaml.security.credential.criteria.impl.EvaluableKeyAlgorithmCredentialCriterion;
+import org.opensaml.security.criteria.KeyAlgorithmCriterion;
 import org.opensaml.security.criteria.UsageCriterion;
 import org.opensaml.xmlsec.algorithm.AlgorithmRegistry;
 import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
@@ -43,14 +44,15 @@ import org.opensaml.xmlsec.impl.AlgorithmRuntimeSupportedPredicate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Strings;
 import com.nimbusds.jose.Algorithm;
 import com.nimbusds.jose.EncryptionMethod;
-import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JWEAlgorithm;
 
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.credential.impl.JWKCredentialSupport;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
+import net.shibboleth.oidc.security.credential.impl.DataEncryptionAlgorithmCriterion;
+import net.shibboleth.oidc.security.credential.impl.KeyManagmentAlgorithmCriterion;
 import net.shibboleth.oidc.security.jose.EncryptionConfiguration;
 import net.shibboleth.oidc.security.jose.EncryptionParameters;
 import net.shibboleth.oidc.security.jose.EncryptionParametersResolver;
@@ -62,7 +64,7 @@ import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
 /**
- * Basic implementation of an {@link EncryptionParametersResolver}. The resolver delegates much of its functionality
+ * Default implementation of an {@link EncryptionParametersResolver}. The resolver delegates much of its functionality
  * to various lookup strategies and credential resolvers. Its main purpose is to compose the results.
  * 
  * <p>The set of usable key transport and data encryption algorithms are determined by injected strategies. The set of
@@ -73,15 +75,13 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
  * <p>Once the set of algorithms and credentials have been looked up and resolved. The key transport algorithms are 
  * tried in the order they are specified until a suitable, compatible, credential is found. It is expected asymmetric
  * encryption keys will be resolved from the OpenID Providers keyset document, and symmetric keys will be derived from
- * the client_secret (although any resolvers could be supplied, and hence this behaviour is not guranteed). </p>
+ * the client_secret (although any resolvers could be supplied, and hence this behaviour is not guaranteed). </p>
  * 
- * <p>Symmetric keys are expected to be returned in their original format. The resolver will derive the correct 
- * symmetric key to add to the correct parameters e.g. for key wrapping and direct content encryption.</p>
+ * <p>Extra criterion are built and provided to the credential resolvers based on the key management mode described
+ * by the algorithms being tested.</p>
  * 
- * <p>Note: the criteria supplied to the credential resolvers should be relatively light on evaluable criterion. 
- * For example, only containing the {@link EvaluableUsageCredentialCriterion} - alongside any non-evaluable 
- * criterion needed by the resolvers. Most of the specific filtering e.g. algorithm and key length, is performed 
- * by this resolver itself based on the logic described by the OpenID specifications.</p>
+ * <p>Symmetric keys are expected to be returned in their final format. For example, symmetric keys derived from the
+ * client_secret are expected to be in a key format ready for decryption.</p>
  * 
  * <p>
  * The following {@link net.shibboleth.utilities.java.support.resolver.Criterion} inputs are supported:
@@ -171,7 +171,6 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
         algorithmRegistry = Constraint.isNotNull(registry, "AlgorithmRegistry was null");
     }
 
-    /** {@inheritDoc} */
     @Override
     @Nonnull public Iterable<EncryptionParameters> resolve(@Nonnull final CriteriaSet criteria) 
             throws ResolverException {
@@ -182,7 +181,6 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
         return Collections.emptyList();
     }
 
-    /** {@inheritDoc} */
     @Override
     @Nullable public EncryptionParameters resolveSingle(@Nonnull final CriteriaSet criteria) 
             throws ResolverException {
@@ -211,7 +209,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
     }
     
     /**
-     * Resolve and return the effective {@link CredentialResolver} used to encrypt content encryption keys.
+     * Resolve and return the effective {@link CredentialResolver} used to encrypt/wrap content encryption keys.
      * 
      * @param criteria the input criteria being evaluated
      * @return the effective resolver, or null
@@ -365,9 +363,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
             criteria.add(new UsageCriterion(UsageType.ENCRYPTION));
         }
         
-        // Pre-resolve these for efficiency
-        final List<Credential> keyTransportCredentials = getEffectiveKeyTransportCredentials(criteria);
-        log.trace("Resolved {} key transport credentials", keyTransportCredentials.size());
+        // Determine the set of transport and content encryption algorithms from the lookup strategies
         final List<String> keyTransportAlgorithms =
                 keyTransportEncryptionAlgorithmsLookupStrategy.apply(criteria, includeExcludePredicate);
         log.trace("Resolved effective key transport algorithms: {}", keyTransportAlgorithms);
@@ -375,26 +371,16 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
         final List<String> dataEncryptionAlgorithms = dataEncryptionAlgorithmsLookupStrategy.apply(criteria, 
                 includeExcludePredicate);
         log.trace("Resolved effective data encryption algorithms: {}", dataEncryptionAlgorithms);
-        final List<Credential> dataEncryptionCredentials = getEffectiveDataEncryptionCredentials(criteria);
-        log.trace("Resolved {} data encryption credentials", dataEncryptionCredentials.size());   
+          
         
         resolveCredentialForSupportedAlgorithm(criteria,
                 convertStringAlgorithmURIsToJwkAlgorithms(keyTransportAlgorithms), 
-                convertStringEncryptionMethodURIsToEncryptionMethods(dataEncryptionAlgorithms),
-                keyTransportCredentials, dataEncryptionCredentials, params);
+                convertStringEncryptionMethodURIsToEncryptionMethods(dataEncryptionAlgorithms), params);
     }
     
     /**
      * Resolve a credential (key) compatible with one-of the supported algorithms. Algorithms are tried in the order
-     * they appear in the list of keyTransportAlgorithms.  
-     * 
-     * <p>Symmetric key algorithms e.g. either for key wrapping or direct content encryption, are passed through a 
-     * key derivation function. It is therefore assumed the input shared secret is the original key e.g. the
-     * raw client_secret.</p>
-     * 
-     * <p>Keys for asymmetric key algorithms are added to the parameter context as is. It is assumed such keys
-     * are taken from the OpenID Provider's keyset document, however any resolver can be used and hence there is
-     * no guarantee of this.</p> 
+     * they appear in the list of keyTransportAlgorithms (key management algorithms). The first compatible is returned. 
      * 
      * <p>The first key that is compatible with the key transport algorithm is returned. That is, if two or more 
      * keys support the same algorithm, the first key resolved will be returned. There is no guarantee which 
@@ -408,122 +394,227 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
      * @param dataEncryptionCredentials the list of local data encryption credentials 
      * @param params the encryption parameters to add the credential to
      */
- // Checkstyle: ParameterNumber|MethodLength|CyclomaticComplexity OFF
     protected void resolveCredentialForSupportedAlgorithm(
             @Nonnull final CriteriaSet criteria,
             @Nonnull final List<JWEAlgorithm> keyTransportAlgorithms,
             @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
-            @Nonnull final List<Credential> keyTransportCredentials, 
-            @Nonnull final List<Credential> dataEncryptionCredentials,
             @Nonnull final EncryptionParameters params) {
         
         for (final JWEAlgorithm algorithm : keyTransportAlgorithms) {  
             
             if (JWEAlgorithm.DIR.equals(algorithm)) {  
-                // Direct content encryption requires a derived key
-                
-                final JWKCredential credential = 
-                        findCredentialThatSupportsAlgorithm(dataEncryptionCredentials, algorithm);               
-                    
-                final EncryptionMethod encryptionMethod = 
-                        findEncryptionMethodThatSupportsCredential(dataEncryptionAlgorithms, credential);
-                
-                final JWKCredential derivedCredential = 
-                        deriveSymmetricKeyForAlgAndEnc(credential, algorithm, encryptionMethod);
-                
-                if (derivedCredential != null) {                      
-                    if (log.isDebugEnabled()) {
-                        log.debug("Derived key from '{}' for alg '{}' and enc '{}'", 
-                                CredentialConversionUtil.resolveKid(credential),
-                                algorithm.getName(), encryptionMethod.getName());
-                    }
-                    
-                    params.setKeyTransportEncryptionAlgorithm(JWEAlgorithm.DIR.getName());
-                    params.setDataEncryptionCredential(derivedCredential);
-                    params.setDataEncryptionAlgorithm(encryptionMethod.getName());
-                    return;                                        
-                } 
-                                 
+                // Direct content encryption
+                if (buildDirectEncryptionParameters(params, criteria, dataEncryptionAlgorithms, algorithm)) {
+                    return;
+                }                  
             } else if (JWEAlgorithm.Family.AES_GCM_KW.contains(algorithm) 
                     || JWEAlgorithm.Family.AES_KW.contains(algorithm)) { 
-                // Key wrapping requires a derived key
-                
-                final JWKCredential credential = 
-                        findCredentialThatSupportsAlgorithm(keyTransportCredentials, algorithm);
-                
-                final EncryptionMethod encryptionMethod = 
-                        resolveEncryptionMethod(dataEncryptionAlgorithms);
-                
-                final JWKCredential derivedCredential = 
-                        deriveSymmetricKeyForAlgAndEnc(credential, algorithm, encryptionMethod);
+                // Key wrapping
+                if (buildKeyWrappingParameters(params, criteria, dataEncryptionAlgorithms, algorithm)) {
+                    return;
+                }
                 
-                if (derivedCredential != null) {                   
+            } else if (JWEAlgorithm.Family.ASYMMETRIC.contains(algorithm)){
+                // Supports key encryption, or key agreement.
+                if (buildKeyEncryptionOrAgreementParameters(params, criteria, dataEncryptionAlgorithms, algorithm)) {
+                    return;
+                }
+            } else {
+                log.trace("Algorithm '{}' is not supported, moving on", algorithm);
+            }            
+        }        
+    }
+    
+    /**
+     * Build direct encryption parameters from the data encryption credentials input. 
+     * 
+     * <p>Note, the symmetric key used is assumed —although not guaranteed— already appropriate for the cryptographic
+     * operation being performed. That is, if a client_secret, the resolvers will derive an appropriate key for the 
+     * encryption algorithm used as no further derivation occurs here. </p> 
+     * 
+     * @param params the parameter context to stash the resolved encryption parameters
+     * @param dataEncryptionAlgorithms the data encryption algorithms
+     * @param dataEncryptionCredentials the data encryption credentials
+     * @param algorithm the direct encryption algorithm
+     */
+    private boolean buildDirectEncryptionParameters(@Nonnull final EncryptionParameters params,
+            @Nonnull final CriteriaSet criteria, @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms, 
+            @Nonnull final JWEAlgorithm algorithm) {
+        
+        
+        for (final EncryptionMethod method : dataEncryptionAlgorithms) {
+            
+            // Resolution must occur for each 'enc' method tested, as the derived direct encryption could be different 
+            // for each.
+            final CriteriaSet credentialCriteria = buildEncryptionKeyAlgorithmCriteria(criteria, algorithm, method);
+            
+            final List<Credential> dataEncryptionCredentials= getEffectiveDataEncryptionCredentials(credentialCriteria);
+            log.trace("Resolved {} possible direct encryption credential(s) for 'alg={}' and 'enc={}'", 
+                    dataEncryptionCredentials.size(), algorithm.getName(), method.getName()); 
+            
+            for (final Credential credential : dataEncryptionCredentials) {
+
+                if (checkCredentialSupportsAlgorithm(credential, algorithm) && 
+                        checkCredentialSupportsEncryptionMethod(credential, method)) {                      
                     if (log.isDebugEnabled()) {
-                        log.debug("Derived key from '{}' for alg '{}' and enc '{}'", 
+                        log.debug("Resolved key from '{}' for 'alg={}' and 'enc={}'", 
                                 CredentialConversionUtil.resolveKid(credential),
-                                algorithm.getName(), encryptionMethod.getName());
+                                algorithm.getName(), method.getName());
                     }
-                    params.setKeyTransportEncryptionCredential(derivedCredential);
-                    params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
-                    params.setDataEncryptionAlgorithm(encryptionMethod.getName());
-                    return;                                       
-               }               
-            } else if (JWEAlgorithm.Family.ASYMMETRIC.contains(algorithm)){
-                // Supports key encryption, or key agreement.
-                final JWKCredential credential = 
-                        findCredentialThatSupportsAlgorithm(keyTransportCredentials, algorithm); 
-                
-                final EncryptionMethod encryptionMethod = 
-                        resolveEncryptionMethod(dataEncryptionAlgorithms);
-                
-                if (credential != null) {                    
-               
+                    
+                    params.setKeyTransportEncryptionAlgorithm(JWEAlgorithm.DIR.getName());
+                    params.setDataEncryptionCredential(credential);
+                    params.setDataEncryptionAlgorithm(method.getName());
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Build key wrapping encryption parameters from the key transport encryption credentials input.
+     * 
+     * <p>Note, the symmetric key used is assumed —although not guaranteed— already appropriate for the cryptographic
+     * operation being performed. That is, if a client_secret, the resolvers will derive an appropriate key for the 
+     * key management algorithm used as no further derivation occurs here. </p> 
+     * 
+     * @param params the parameter context to stash the resolved encryption parameters
+     * @param dataEncryptionAlgorithms the data encryption algorithms
+     * @param keyTransportCredentials the key transport encryption credentials
+     * @param algorithm the key wrapping algorithm
+     */
+    private boolean buildKeyWrappingParameters(@Nonnull final EncryptionParameters params,
+            @Nonnull final CriteriaSet criteria, @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms, 
+            @Nonnull final JWEAlgorithm algorithm) {
+        
+        
+        for (final EncryptionMethod method : dataEncryptionAlgorithms) {
+            
+            final CriteriaSet credentialCriteria = buildKeyManagmentAlgorithmCriteria(criteria, algorithm, method);
+     
+            final List<Credential> keyTransportCredentials = getEffectiveKeyTransportCredentials(credentialCriteria);
+            log.trace("Resolved {} possible key transport credentials for 'alg={}' and 'enc={}'", 
+                    keyTransportCredentials.size(), algorithm.getName(), method.getName());
+            
+            for (final Credential credential : keyTransportCredentials) {
+
+                if (checkCredentialSupportsAlgorithm(credential, algorithm) && 
+                        checkCredentialSupportsEncryptionMethod(credential, method)) {                      
                     if (log.isDebugEnabled()) {
-                        log.debug("Selected key '{}' for alg '{}' and enc '{}'", 
+                        log.debug("Resolved key from '{}' for 'alg={}' and 'enc={}'", 
                                 CredentialConversionUtil.resolveKid(credential),
-                                algorithm.getName(), encryptionMethod.getName());
+                                algorithm.getName(), method.getName());
                     }
+                    
                     params.setKeyTransportEncryptionCredential(credential);
                     params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
-                    params.setDataEncryptionAlgorithm(encryptionMethod.getName());
-                    return;
-                } 
-            } else {
-                log.trace("Algorithm '{}' is not supported, moving on", algorithm);
-            }            
+                    params.setDataEncryptionAlgorithm(method.getName());  
+                    return true;
+                }
+            }
+        }
+        return false;          
+    }
+    
+    /**
+     * Build key encryption parameters from the key transport encryption credentials input. 
+     * 
+     * @param params the parameter context to stash the resolved encryption parameters
+     * @param dataEncryptionAlgorithms the data encryption algorithms
+     * @param algorithm the key encryption algorithm
+     */
+    private boolean buildKeyEncryptionOrAgreementParameters(@Nonnull final EncryptionParameters params,
+            @Nonnull final CriteriaSet criteria,  @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms, 
+            @Nonnull final JWEAlgorithm algorithm) {
+        
+        
+        final EncryptionMethod encryptionMethod = resolveEncryptionMethod(dataEncryptionAlgorithms);
+        
+        final List<Credential> keyTransportCredentials = getEffectiveKeyTransportCredentials(
+                buildKeyManagmentAlgorithmCriteria(criteria, algorithm, encryptionMethod));
+        
+        log.trace("Resolved {} possible key transport credentials for 'alg={}'", 
+                keyTransportCredentials.size(), algorithm.getName());
+
+        for (final Credential credential : keyTransportCredentials) {
+
+            if (checkCredentialSupportsAlgorithm(credential, algorithm)) {                      
+                if (log.isDebugEnabled()) {
+                    log.debug("Resolved key from '{}' for 'alg={}' and 'enc={}'", 
+                            CredentialConversionUtil.resolveKid(credential),
+                            algorithm.getName(), encryptionMethod.getName());
+                }
+                
+                params.setKeyTransportEncryptionCredential(credential);
+                params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
+                params.setDataEncryptionAlgorithm(encryptionMethod.getName());  
+                return true;
+            }
         }        
+        return false;          
     }
- // Checkstyle: ParameterNumber|MethodLength|CyclomaticComplexity ON 
+    
     /**
-     * Wrapper to 
-     * {@link JWKCredentialSupport#deriveSymmetricKeyForAlgAndEnc(JWKCredential, JWEAlgorithm, EncryptionMethod)}
-     * which derives a *new* symmetric key credential suitable for the given 'alg' and 'enc' algorithms. Catches 
-     * and logs errors, returning {@literal null} on error.
+     * Build criterion for credential resolvers from the JWE 'alg' header. These describe the algorithm used to decrypt
+     * or determine the value of the content/data encryption key.
      * 
-     * @param credential the credential that contains a secret key to derive a new credential from
-     * @param alg the key management mode algorithm
-     * @param enc the content encryption algorithm
+     * @param existingCriteria any existing criterion passed into this resolver.
+     * @param alg the JWE algorithm
+     * @param enc the JWE encryption algorithm
      * 
-     * @return a *new* derived credential, or {@code null} if an error occurs
+     * @return a criteria set with algorithm specific criterion
      */
-    @Nullable private JWKCredential deriveSymmetricKeyForAlgAndEnc(
-            @Nullable final JWKCredential credential, @Nullable final JWEAlgorithm alg, 
-            @Nullable final EncryptionMethod enc) {
-        
-        try {
-            return JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(credential, alg, enc);
-        } catch (final JOSEException e) {
-            log.warn("Unable to generate secret key: {}", e.getMessage());
-            return null;
+    private CriteriaSet buildKeyManagmentAlgorithmCriteria(@Nonnull final CriteriaSet existingCriteria, 
+            @Nonnull final JWEAlgorithm alg, @Nonnull final EncryptionMethod enc) {
+        
+        final CriteriaSet credentialCriteria = new CriteriaSet();
+        credentialCriteria.addAll(existingCriteria);
+        
+        credentialCriteria.add(new KeyManagmentAlgorithmCriterion(alg.getName()));
+        credentialCriteria.add(new DataEncryptionAlgorithmCriterion(enc.getName()));
+        
+        final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(alg.getName());
+        if (!Strings.isNullOrEmpty(jcaKeyAlgorithm)) {
+            credentialCriteria.add(new EvaluableKeyAlgorithmCredentialCriterion(
+                    new KeyAlgorithmCriterion(jcaKeyAlgorithm)));
         }
+        return credentialCriteria;
+        
+    }
     
+    /**
+     * Build criterion for credential resolvers from the JWE 'enc' header. These describe the content encryption 
+     * algorithm used to decrypt the cipher text inside the JWE.
+     * 
+     * @param existingCriteria any existing criterion passed into this resolver.
+     * @param alg the JWE algorithm
+     * @param enc the JWE encryption algorithm
+     * 
+     * @return a criteria set with algorithm specific criterion
+     */
+    private CriteriaSet buildEncryptionKeyAlgorithmCriteria(@Nonnull final CriteriaSet existingCriteria, 
+            @Nonnull final JWEAlgorithm alg, @Nonnull final EncryptionMethod enc) {
+        
+        final CriteriaSet credentialCriteria = new CriteriaSet();
+        credentialCriteria.addAll(existingCriteria);
+        
+        credentialCriteria.add(new KeyManagmentAlgorithmCriterion(alg.getName()));
+        credentialCriteria.add(new DataEncryptionAlgorithmCriterion(enc.getName()));
+        
+        final String jcaEncAlgorithm = AlgorithmSupport.getKeyAlgorithm(enc.getName());
+        if (!Strings.isNullOrEmpty(jcaEncAlgorithm)) {
+            credentialCriteria.add(new EvaluableKeyAlgorithmCredentialCriterion(
+                    new KeyAlgorithmCriterion(jcaEncAlgorithm)));
+        }
+        return credentialCriteria;
+        
     }
     
-
     /**
-     * Determine if any of the given credentials match the given algorithm.
+     * Determine if the given credential matches the given algorithm.
      * 
-     * <p>For a credential to be returned, it must meet the following criteria:</p>
+     * <p>For a credential to match, it must meet the following criteria:</p>
      * <ol>
      * <li>The credential must be a {@link JWKCredential}</li>
      * <li>The credential must have a {@link UsageType} of {@link UsageType#ENCRYPTION} 
@@ -533,33 +624,53 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
      * <li>The credential's key must match the keylength required by that algorithm</li>
      * </ol>
      * 
-     * <p>The first key that is compatible with the algorithm is returned. That is, if two or more keys
-     * support the same algorithm, the first key in the local credentials list
-     * will be returned. There is no guarantee which key that is.</p>
-     * 
-     * @param credentials the credentials to match against the algorithm
-     * @param algorithm the algorithm to locate a credential for
+     * @param credential the credential to match against the algorithm
+     * @param algorithm the algorithm the credential must support
      * 
-     * @return the first credential that matches the algorithm, {@literal null} otherwise.
+     * @return true if the credential supports the given algorithm, false otherwise
      */
-    //TODO the keys should already match the ENC usage, so that should be a redundant check
-    //TODO maybe this logic could be build into EvaluableCriterion for the resolvers.
-    @Nullable protected JWKCredential findCredentialThatSupportsAlgorithm(@Nonnull final  List<Credential> credentials,
+    protected boolean checkCredentialSupportsAlgorithm(@Nonnull final Credential credential, 
             @Nonnull final JWEAlgorithm algorithm) {
-        return credentials.stream()
-                .filter(Objects::nonNull)
-                .filter(JWKCredential.class::isInstance)
-                .filter(k -> UsageType.ENCRYPTION == k.getUsageType() ||  UsageType.UNSPECIFIED == k.getUsageType())
-                .map(JWKCredential.class::cast)
-                .filter(k -> checkKeyWithAlgorithm(k, algorithm))
-                .filter(k -> checkKeyAlgorithmAndLength(k, algorithm.getName()))
-                .findFirst().orElse(null);
+        
+        if (!(credential instanceof JWKCredential)) {
+            return false;
+        }
+        if (credential.getUsageType() != UsageType.ENCRYPTION && credential.getUsageType() != UsageType.UNSPECIFIED) {
+            return false;
+        }
+        if (!checkKeyWithAlgorithm((JWKCredential)credential, algorithm)) {
+            return false;
+        }
+        if (!checkKeyAlgorithmAndLength(credential, algorithm.getName())) {
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+     * Determine if the given credential supports the given encryption method.
+     * 
+     * <p>For a credential to match, it must meet the following criteria:</p>
+     * <ol>
+     * <li>The credential's key algorithm and key length must match that required by the encryption algorithm given</li>
+     * </ol>
+     * 
+     * @param credential the credential to match against the algorithm
+     * @param encMethod the encryption algorithm the credential must support
+     * 
+     * @return true if the credential supports the given algorithm, false otherwise
+     */
+    protected boolean checkCredentialSupportsEncryptionMethod(@Nonnull final Credential credential, 
+            @Nonnull final EncryptionMethod encMethod) {
+        
+        final Key key = CredentialSupport.extractEncryptionKey(credential);
+        return AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(encMethod.getName()));
     }
     
     /**
-     * Check the credential supports the algorithm given. If the algorithm is present, check that is 
-     * identical to the algorithm supplied. If not, check the key algorithm is compatible with the algorithm 
-     * family.
+     * Check the credential supports the algorithm given. If the exact algorithm the key supports is present, check 
+     * that is identical to the algorithm supplied. If not, check the key algorithm is generally compatible with the 
+     * algorithm family.
      * 
      * @param credential the credential to check
      * @param algorithm the algorithm to check compatibility with
@@ -585,33 +696,9 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
         return false;
 
     }
-    
-    /**
-     * Find an encryption method that is supported by the credential. That is, supports the algorithm and
-     * has the correct key length.
-     * 
-     * @param dataEncryptionAlgorithms the data encryption algorithms
-     * @param credential the credential to test
-     * 
-     * @return the first supported encryption method, {@literal null} otherwise.
-     */
-    @Nullable private EncryptionMethod findEncryptionMethodThatSupportsCredential(
-            @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
-            @Nonnull final Credential credential) {
-        
-        final Key key = CredentialSupport.extractEncryptionKey(credential);
-        
-        for (final EncryptionMethod method : dataEncryptionAlgorithms) {
-            if (AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(method.getName()))) {
-                return method;
-            }
-        }
-        return null;
-        
-    }
 
     /**
-     * Get the effective list of data encryption credentials to consider.
+     * Get the effective list of data/content encryption credentials to consider.
      * 
      * @param criteria the input criteria being evaluated
      * 
@@ -673,7 +760,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
     }
     
     /**
-     * Convert the algorithms represented as strings, into Nimbus {@link Algorithm}s for later comparison.
+     * Convert the algorithms represented as Strings into Nimbus {@link Algorithm}s for later comparison.
      * This will preserve the order of the original list ({@link List} is ordered). 
      * 
      * @param algos the algorithms to convert
@@ -685,7 +772,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
     }
     
     /**
-     * Convert the encryption methods represented as strings, into Nimbus {@link EncryptionMethod}s for later 
+     * Convert the encryption methods represented as Strings into Nimbus {@link EncryptionMethod}s for later 
      * comparison. This will preserve the order of the original list ({@link List} is ordered). 
      * 
      * @param encMethods the encryption methods to convert
@@ -741,7 +828,12 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
             return false;
         }
         
-        return AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(algorithm));
+        final boolean valid =  AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(algorithm));
+        if (!valid) {
+            log.trace("Key '{}' does not match algorithm and key length requirement for '{}'", 
+                    CredentialConversionUtil.resolveKid(credential), algorithm);
+        }
+        return valid;
     }
     
     
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolverTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolverTest.java
new file mode 100644
index 0000000..6021c42
--- /dev/null
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolverTest.java
@@ -0,0 +1,227 @@
+
+package net.shibboleth.oidc.security.credential.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+
+import javax.crypto.SecretKey;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
+import org.testng.annotations.Test;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.JWEHeader;
+import com.nimbusds.jose.JWEObject;
+import com.nimbusds.jose.JWEObject.State;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.KeyLengthException;
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.crypto.AESDecrypter;
+import com.nimbusds.jose.crypto.AESEncrypter;
+import com.nimbusds.jose.crypto.MACSigner;
+import com.nimbusds.jwt.EncryptedJWT;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.auth.Secret;
+import com.nimbusds.oauth2.sdk.jose.SecretKeyDerivation;
+
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/** Tests for {@link ClientSecretCriterionCredentialResolver}. */
+public class ClientSecretCriterionCredentialResolverTest {
+
+    private static final String CLIENT_SECRET = "aPdSgVkXp2s5v8y/B?E(H+MbQeThWmZq";
+
+    /** Resolver to test. */
+    private ClientSecretCriterionCredentialResolver resolver;
+    
+    @Test
+    public void testResolveSigningKey() throws ResolverException {
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.SIGNING);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+        
+        assertNotNull(resolvedCredentials);
+        assertTrue(resolvedCredentials.iterator().hasNext());
+        final Credential cred = resolvedCredentials.iterator().next();
+        assertNotNull(cred);
+        assertNotNull(cred.getSecretKey());
+        assertEquals(cred.getSecretKey().getAlgorithm(), "NONE");
+        assertEquals(cred.getSecretKey().getEncoded().length, 32);
+        assertEquals(cred.getUsageType(), UsageType.SIGNING);
+
+    }
+    
+    @Test(expectedExceptions = ResolverException.class)
+    public void testResolveIncompatibleUsageType() throws ResolverException {
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.UNSPECIFIED);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+        set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+    }
+    
+    @Test(expectedExceptions = ResolverException.class)
+    public void testResolveNoKeyAlogrithmCriterion() throws ResolverException {
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        
+        set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+    }
+    
+    @Test(expectedExceptions = ResolverException.class)
+    public void testResolveNoDataEncryptionAlogrithmCriterion() throws ResolverException {
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+    }
+
+    @Test
+    public void testResolveKeyWrappingKey() throws ResolverException {
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+        set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+        
+        assertNotNull(resolvedCredentials);
+        assertTrue(resolvedCredentials.iterator().hasNext());
+        final Credential cred = resolvedCredentials.iterator().next();
+        assertNotNull(cred);
+        assertNotNull(cred.getSecretKey());
+        assertEquals(cred.getSecretKey().getAlgorithm(), "AES");
+        assertEquals(cred.getSecretKey().getEncoded().length, 16);
+        assertEquals(cred.getUsageType(), UsageType.ENCRYPTION);
+
+    }
+    
+    /* Test the derived key is indeed compatible with a derived decryption key.*/
+    @Test
+    public void testResolveKeyWrappingKey_Decrypts() throws Exception {
+        
+
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A128KW, EncryptionMethod.A128GCM)
+                .contentType("JWT")
+                .keyID("mock-key")
+                .build(),
+                new Payload(createdSignedJWT()));
+        
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+        set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128GCM.getName()));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+        
+        assertNotNull(resolvedCredentials);
+        assertTrue(resolvedCredentials.iterator().hasNext());
+        final Credential cred = resolvedCredentials.iterator().next();
+        assertNotNull(cred);
+        assertNotNull(cred.getSecretKey());
+        assertEquals(cred.getSecretKey().getAlgorithm(), "AES");
+        assertEquals(cred.getSecretKey().getEncoded().length, 16);
+        assertEquals(cred.getUsageType(), UsageType.ENCRYPTION);
+        
+        jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        
+        final SecretKey key = SecretKeyDerivation.deriveSecretKey(new Secret(CLIENT_SECRET), JWEAlgorithm.A128KW, 
+                EncryptionMethod.A128GCM);
+        
+        jwe.decrypt(new AESDecrypter(key));
+        assertTrue(jwe.getState() == State.DECRYPTED);
+        final SignedJWT jws =jwe.getPayload().toSignedJWT();
+        assertEquals(jws.getJWTClaimsSet().getSubject(), "jdoe");
+
+    }
+    
+    private SignedJWT createdSignedJWT() throws KeyLengthException, JOSEException {        
+        final var header = new JWSHeader.Builder(JWSAlgorithm.HS256)
+                .type(JOSEObjectType.JWT)
+                .keyID("mock-key")
+                .build();       
+        final var signedJWT = new SignedJWT(header,createClaims());
+        signedJWT.sign(new MACSigner(CLIENT_SECRET));
+        return signedJWT;
+    }
+    
+    private JWTClaimsSet createClaims() {
+        return new JWTClaimsSet.Builder()
+                .issuer("https://localhost:9918")
+                .audience(List.of("test-client"))
+                .subject("jdoe")
+                .claim("nonce", "abadnonce")
+                .claim("azp", "test-client")
+                .claim("name","jdoe")
+                .expirationTime(Date.from(Instant.now().plusSeconds(120)))
+                .build();
+    }
+    
+    @Test
+    public void testResolveDirectEncryptionKey() throws ResolverException {
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.DIR.getName()));
+        set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+        
+        assertNotNull(resolvedCredentials);
+        assertTrue(resolvedCredentials.iterator().hasNext());
+        final Credential cred = resolvedCredentials.iterator().next();
+        assertNotNull(cred);
+        assertNotNull(cred.getSecretKey());
+        assertEquals(cred.getSecretKey().getEncoded().length, 32);
+        assertEquals(cred.getSecretKey().getAlgorithm(), "AES");
+        assertEquals(cred.getUsageType(), UsageType.ENCRYPTION);
+
+    }
+    
+    /* Should fail, as asymmetric key can not be created from client_secret.*/
+    @Test
+    public void testIncompatibleAlg() throws ResolverException {
+        resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+        final CriteriaSet set = new CriteriaSet();
+        set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+        set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.RSA_OAEP_256.getName()));
+        set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+        final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+        
+        assertNotNull(resolvedCredentials);
+        assertFalse(resolvedCredentials.iterator().hasNext());
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java
index e6c363e..2646f8a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java
@@ -31,6 +31,7 @@ import org.opensaml.messaging.handler.MessageHandlerException;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.nimbusds.jose.EncryptionMethod;
 import com.nimbusds.jose.JWEAlgorithm;
 import com.nimbusds.jose.JWEObject.State;
 import com.nimbusds.jose.Payload;
@@ -224,7 +225,8 @@ public class EncryptJWTHandlerTest extends AbstractHandlerTest {
         params.setKeyTransportEncryptionAlgorithm(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW);
 
         final var kwCred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET);
-        params.setKeyTransportEncryptionCredential(kwCred);
+        final var derivedKey = kwCred.toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM);
+        params.setKeyTransportEncryptionCredential(derivedKey);
         
      
         secParamCtx.setEncryptionParameters(params);  
@@ -238,7 +240,7 @@ public class EncryptJWTHandlerTest extends AbstractHandlerTest {
         assertTrue(jwt instanceof EncryptedJWT);
         final var encryptedJWT = (EncryptedJWT)jwt;
 
-        final AESDecrypter testDecrypter = new AESDecrypter(kwCred.getSecretKey());
+        final AESDecrypter testDecrypter = new AESDecrypter(derivedKey.getSecretKey());
         encryptedJWT.decrypt(testDecrypter);
         
         assertStandardClaimsExist(encryptedJWT);
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
index eced91a..5112c6a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
@@ -151,8 +151,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
             public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
                 try {
                     return TestCredentialHelper
-                            .createSharedSecretCredential("mockKey", CLIENT_SECRET, 
-                                    JWSAlgorithm.HS256, UsageType.SIGNING);
+                            .createClientSecretCredential(CLIENT_SECRET).toSigningCredential();
                 } catch (final KeyException e) {
                     fail(e.getMessage());
                     return null;
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypterTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWETokenDecrypterTest.java
similarity index 80%
rename from oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypterTest.java
rename to oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWETokenDecrypterTest.java
index 41c5bc1..faee700 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypterTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWETokenDecrypterTest.java
@@ -6,6 +6,9 @@ import static org.testng.Assert.fail;
 
 import java.nio.charset.StandardCharsets;
 import java.security.KeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
 import java.security.interfaces.RSAPublicKey;
 import java.text.ParseException;
 import java.time.Instant;
@@ -14,7 +17,9 @@ import java.util.Date;
 import java.util.List;
 
 import org.opensaml.core.config.InitializationException;
+import org.opensaml.security.credential.BasicCredential;
 import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
 import org.opensaml.security.credential.impl.AbstractCriteriaFilteringCredentialResolver;
 import org.opensaml.security.crypto.KeySupport;
 import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
@@ -50,18 +55,18 @@ import com.nimbusds.jwt.JWT;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.SignedJWT;
 
+import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
 import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.credential.impl.JWKCredentialSupport;
 import net.shibboleth.oidc.security.jose.DecryptionParameters;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
-/** Tests for the {@link OIDCTokenDecrypter}.*/
-public class OIDCTokenDecrypterTest {
+/** Tests for the {@link JWETokenDecrypter}.*/
+public class JWETokenDecrypterTest {
     
-    private OIDCTokenDecrypter decrypter;
+    private JWETokenDecrypter decrypter;
     
     private static final String CLIENT_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
     
@@ -111,7 +116,7 @@ public class OIDCTokenDecrypterTest {
         jweObject.encrypt(new PasswordBasedEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8),8,1000));
         final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());        
        
-        decrypter = new OIDCTokenDecrypter(new DecryptionParameters());
+        decrypter = new JWETokenDecrypter(new DecryptionParameters());
         decrypter.decrypt(jwe);
     }
     
@@ -121,12 +126,11 @@ public class OIDCTokenDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
                 .contentType("JWT")
-                .keyID("mock-key")
+                .keyID("client_secret_credential")
                 .build(),
                 new Payload(createdSignedJWT()));
-        final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
-                TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR, 
-                EncryptionMethod.A256GCM);
+        final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
         jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
         final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
         
@@ -135,17 +139,13 @@ public class OIDCTokenDecrypterTest {
             
             @Override
             public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
-                final BasicJWKCredential jwkCredential = new BasicJWKCredential();
-                jwkCredential.setAlgorithm(JWEAlgorithm.A256KW);
-                jwkCredential.getKeyNames().add("mock-key");
-                jwkCredential.setKid("mock-key");
                 try {
-                    jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
-                            JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
-                } catch (final KeyException e) {
-                    throw new ResolverException(e);
-                }           
-                return jwkCredential;
+                    return TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                            .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+                } catch (KeyException | JOSEException e) {
+                    fail();
+                    return null;
+                }
             }
             
             @Override
@@ -153,7 +153,7 @@ public class OIDCTokenDecrypterTest {
                 return List.of(resolveSingle(criteria));
             }
         });
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
@@ -166,24 +166,63 @@ public class OIDCTokenDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
                 .contentType("JWT")
-                .keyID("mock-key")
+                .keyID("client_secret_credential")
                 .build(),
                 new Payload(createdSignedJWT()));
-        final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
-                TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR, 
-                EncryptionMethod.A256GCM);
+        final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
         jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
         final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
         
         final var params = new DecryptionParameters();
         params.setKEKCredentialResolver(new MockKeyWrapCriteriaFilteringCredentialResolver());
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
         assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
     }
     
+    @Test(expectedExceptions = DecryptionException.class)
+    void testDecryptionByKeyWrapping_WrongCredentialType() throws Exception {       
+        
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
+                .contentType("JWT")
+                .keyID("client_secret_credential")
+                .build(),
+                new Payload(createdSignedJWT()));
+        final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+        jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        
+        final var params = new DecryptionParameters();
+        params.setKEKCredentialResolver(new JOSEObjectCredentialResolver() {
+            
+            @Override
+            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+                try {
+                    final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+                    generator.initialize(2048);
+                    final KeyPair keyPair = generator.generateKeyPair();
+                    return new BasicCredential(keyPair.getPublic(), keyPair.getPrivate());                    
+                } catch (final NoSuchAlgorithmException e) {
+                    fail();
+                    return null;
+                }
+            }
+            
+            @Override
+            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+                return List.of(resolveSingle(criteria));
+            }
+        });
+        decrypter = new JWETokenDecrypter(params);
+        final JWT decryptedJWE = decrypter.decrypt(jwe);
+
+    }
+    
     @Test
     void testDecryptionByDirectEncryption() throws Exception {       
         
@@ -195,9 +234,9 @@ public class OIDCTokenDecrypterTest {
                 new Payload(createdSignedJWT()));
         
         
-        final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
-                TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR, 
-                EncryptionMethod.A256GCM);
+        final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+        
         jweObject.encrypt(new DirectEncrypter(cred.getSecretKey()));
         final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
         
@@ -206,17 +245,13 @@ public class OIDCTokenDecrypterTest {
             
             @Override
             public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
-                final BasicJWKCredential jwkCredential = new BasicJWKCredential();
-                jwkCredential.setAlgorithm(JWEAlgorithm.DIR);
-                jwkCredential.getKeyNames().add("mock-key");
-                jwkCredential.setKid("mock-key");
                 try {
-                    jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
-                            JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
-                } catch (final KeyException e) {
-                    throw new ResolverException(e);
-                }          
-                return jwkCredential;
+                    return TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                            .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+                } catch (KeyException | JOSEException e) {
+                    fail();
+                    return null;
+                }
             }
             
             @Override
@@ -224,13 +259,52 @@ public class OIDCTokenDecrypterTest {
                 return List.of(resolveSingle(criteria));
             }
         });
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
         assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
     }
     
+    @Test(expectedExceptions = DecryptionException.class)
+    void testDecryptionByDirectEncryption_SecretKeyIsNull() throws Exception {       
+        
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
+                .contentType("JWT")
+                .keyID("mock-key")
+                .build(),
+                new Payload(createdSignedJWT()));
+        
+        
+        final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+        
+        jweObject.encrypt(new DirectEncrypter(cred.getSecretKey()));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        
+        final var params = new DecryptionParameters();
+        params.setContentEncryptionKeyCredentialResolver(new JOSEObjectCredentialResolver() {
+            
+            @Override
+            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {                
+                final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential(); 
+                jwkCredential.getKeyNames().add("mock-key"); 
+                jwkCredential.setKid("mock-key");
+                jwkCredential.setUsageType(UsageType.ENCRYPTION); 
+                return  jwkCredential;                
+            }
+            
+            @Override
+            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+                return List.of(resolveSingle(criteria));
+            }
+        });
+        decrypter = new JWETokenDecrypter(params);
+        final JWT decryptedJWE = decrypter.decrypt(jwe);
+
+    }
+    
     
     @Test
     void testDecryptionByDirectEncryption_Using_EvaluableCriteriaFiltering() throws Exception {       
@@ -238,18 +312,17 @@ public class OIDCTokenDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
                 .contentType("JWT")
-                .keyID("mock-key")
+                .keyID("client_secret_credential")
                 .build(),
                 new Payload(createdSignedJWT()));
-        final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
-                TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR, 
-                EncryptionMethod.A256GCM);
+        final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
         jweObject.encrypt(new DirectEncrypter(cred.getSecretKey()));
         final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
         
         final var params = new DecryptionParameters();
-        params.setContentEncryptionKeyCredentialResolver(new MockDirCriteriaFilteringCredentialResolver());
-        decrypter = new OIDCTokenDecrypter(params);
+        params.setContentEncryptionKeyCredentialResolver(new MockKeyWrapCriteriaFilteringCredentialResolver());
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
@@ -295,7 +368,7 @@ public class OIDCTokenDecrypterTest {
         // Include the 'enc' algorithm but not the 'alg' algorithm. So decrypt should fail.
         params.setIncludedAlgorithms(List.of("A256GCM"));
         try {
-            decrypter = new OIDCTokenDecrypter(params);
+            decrypter = new JWETokenDecrypter(params);
             decrypter.decrypt(jwe);
         } catch (final DecryptionException e) {
             // Do nothing, JWE should not be decrypted.
@@ -340,7 +413,7 @@ public class OIDCTokenDecrypterTest {
             }
         });
         try {
-            decrypter = new OIDCTokenDecrypter(params);
+            decrypter = new JWETokenDecrypter(params);
             decrypter.decrypt(jwe);
         } catch (final DecryptionException e) {
             // Do nothing, JWE should not be decrypted.
@@ -383,7 +456,7 @@ public class OIDCTokenDecrypterTest {
                 return List.of(resolveSingle(criteria));
             }
         });
-        decrypter = new OIDCTokenDecrypter(params);       
+        decrypter = new JWETokenDecrypter(params);       
         try {
             decrypter.decrypt(jwe);
         } catch (final DecryptionException e) {
@@ -432,13 +505,15 @@ public class OIDCTokenDecrypterTest {
                 return List.of(resolveSingle(criteria));
             }
         });
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
         assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");    
     }
     
+    
+    
     /* Same as testDecryptionByKeyEncryption but using a resolver that supports credential filtering.*/
     @Test
     void testDecryptionByKeyEncryption_Using_EvaluableCriteriaFiltering() throws Exception  {       
@@ -458,7 +533,7 @@ public class OIDCTokenDecrypterTest {
         final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
         final var params = new DecryptionParameters();
         params.setKEKCredentialResolver(new MockRSACriteriaFilteringCredentialResolver(key));
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
@@ -494,7 +569,7 @@ public class OIDCTokenDecrypterTest {
         
         final var params = new DecryptionParameters();
         params.setKEKCredentialResolver(new MockRSAKeysCriteriaFilteringCredentialResolver(List.of(key, keyTwo)));
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
@@ -527,7 +602,7 @@ public class OIDCTokenDecrypterTest {
         
         final var params = new DecryptionParameters();        
         params.setKEKCredentialResolver(new MockRSAKeysCriteriaFilteringCredentialResolver(List.of(key, keyTwo)));
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
@@ -574,7 +649,7 @@ public class OIDCTokenDecrypterTest {
                 return List.of(resolveSingle(criteria));
             }
         });
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
@@ -600,7 +675,7 @@ public class OIDCTokenDecrypterTest {
         final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
         final var params = new DecryptionParameters();
         params.setKEKCredentialResolver(new MockKeyAgreementCriteriaFilteringCredentialResolver(key));
-        decrypter = new OIDCTokenDecrypter(params);
+        decrypter = new JWETokenDecrypter(params);
         final JWT decryptedJWE = decrypter.decrypt(jwe);
         assertTrue(jwe.getState() == State.DECRYPTED);
         assertTrue(decryptedJWE instanceof SignedJWT);
@@ -665,43 +740,20 @@ public class OIDCTokenDecrypterTest {
         }
         
     }
-    
-    private static class MockDirCriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
-        implements JOSEObjectCredentialResolver {
-    
-        @Override
-        protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
-            final BasicJWKCredential jwkCredential = new BasicJWKCredential();
-            jwkCredential.setAlgorithm(JWEAlgorithm.DIR);
-            jwkCredential.getKeyNames().add("mock-key");
-            jwkCredential.setKid("mock-key");
-            try {
-                jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
-                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
-            } catch (final KeyException e) {
-                throw new ResolverException(e);
-            }          
-            return List.of(jwkCredential);
-        }
-    
-    }
+
     
     private static class MockKeyWrapCriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
         implements JOSEObjectCredentialResolver {
 
         @Override
         protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
-            final BasicJWKCredential jwkCredential = new BasicJWKCredential();
-            jwkCredential.setAlgorithm(JWEAlgorithm.A256KW);
-            jwkCredential.getKeyNames().add("mock-key");
-            jwkCredential.setKid("mock-key");
             try {
-                jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
-                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
-            } catch (final KeyException e) {
-                throw new ResolverException(e);
-            }           
-            return List.of(jwkCredential);
+                return List.of(TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+                        .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM));
+            } catch (KeyException | JOSEException e) {
+                fail();
+                return null;
+            }
         }
 
     }
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java
index c89aae0..a8e4872 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java
@@ -97,7 +97,8 @@ public class SignJWTHandlerTest extends AbstractHandlerTest {
         
         final SecurityParametersContext secParamCtx = new SecurityParametersContext();
         final var params = new SignatureSigningParameters();
-        params.setSigningCredential(TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET));
+        params.setSigningCredential(
+                TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET).toSigningCredential());
         params.setSignatureAlgorithm("HS256");
         secParamCtx.setSignatureSigningParameters(params);        
         prc.getOutboundMessageContext().addSubcontext(secParamCtx);
@@ -115,7 +116,8 @@ public class SignJWTHandlerTest extends AbstractHandlerTest {
         
         final SecurityParametersContext secParamCtx = new SecurityParametersContext();
         final var params = new SignatureSigningParameters();
-        params.setSigningCredential(TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET));
+        params.setSigningCredential(
+                TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET).toSigningCredential());
         params.setSignatureAlgorithm("RS256");
         secParamCtx.setSignatureSigningParameters(params);        
         prc.getOutboundMessageContext().addSubcontext(secParamCtx);
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java
index 54a68b3..65be91a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java
@@ -24,7 +24,6 @@ import java.time.Duration;
 import org.opensaml.security.credential.UsageType;
 import org.opensaml.security.crypto.KeySupport;
 
-import com.nimbusds.jose.Algorithm;
 import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JWEAlgorithm;
 import com.nimbusds.jose.jwk.AsymmetricJWK;
@@ -33,6 +32,8 @@ import com.nimbusds.jose.jwk.JWK;
 import com.nimbusds.jose.jwk.RSAKey;
 
 import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
 import net.shibboleth.oidc.security.credential.JWKCredential;
 
 /** Helper that creates different credentials.*/
@@ -42,36 +43,9 @@ public final class TestCredentialHelper {
         
     }
     
-    /**
-     * Create a simple symmetric key client credential from from the given shared secret.
-     * 
-     * @param secret the secret to convert to a {@link JWKCredential}.
-     * 
-     * @return the credential
-     * @throws KeyException on error creating the key
-     */
-    public static JWKCredential createClientSecretCredential(final String secret) throws KeyException {        
-        return createClientSecretCredential("mockKey", secret, null);
-    }
-    
-    /**
-     * Create a simple symmetric key client credential from from the given shared secret.
-     * 
-     * @param kid the key ID
-     * @param secret the secret to convert to a {@link JWKCredential}.
-     * @param algorithm the JWA algorithm to set on the credential.
-     * 
-     * @return the credential
-     * @throws KeyException on error creating the key
-     */
-    public static JWKCredential createClientSecretCredential(final String kid, final String secret, 
-            final Algorithm algorithm) 
-            throws KeyException {
-        return createSharedSecretCredential(kid, secret, algorithm, UsageType.UNSPECIFIED);
-    }
     
     /**
-     * Create a simple symmetric key client credential from from the given shared secret.
+     * Create a simple symmetric key client_secret credential from from the given shared secret.
      * 
      * @param kid the key ID
      * @param secret the secret to convert to a {@link JWKCredential}.
@@ -80,17 +54,9 @@ public final class TestCredentialHelper {
      * @return the credential
      * @throws KeyException on error creating the key
      */
-    public static JWKCredential createSharedSecretCredential(final String kid, final String secret, 
-            final Algorithm algorithm, final UsageType usage) 
+    public static ClientSecretCredential createClientSecretCredential(final String secret) 
             throws KeyException {
-        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
-        jwkCredential.setSecretKey(KeySupport.decodeSecretKey(JWSAssemblyUtils.getSecretBytes(secret), "AES"));
-        jwkCredential.setCredentialExpiresAt(Duration.ZERO);
-        jwkCredential.setUsageType(usage);
-        jwkCredential.setKid(kid);
-        jwkCredential.setAlgorithm(algorithm);
-        jwkCredential.getKeyNames().add("mockKey");
-        return jwkCredential;
+        return new DefaultClientSecretCredential(secret);
     }
     
     /**
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java
index d5b0c65..2d8902a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java
@@ -37,6 +37,7 @@ import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.nimbusds.jose.EncryptionMethod;
 import com.nimbusds.jose.JWEAlgorithm;
 import com.nimbusds.jose.jwk.Curve;
 import com.nimbusds.jose.jwk.ECKey;
@@ -48,14 +49,14 @@ import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
 import net.shibboleth.oidc.jwa.support.EncryptionConstants;
 import net.shibboleth.oidc.jwa.support.KeyManagementConstants;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
 import net.shibboleth.oidc.security.credential.JWKCredential;
 import net.shibboleth.oidc.security.impl.TestCredentialHelper;
 import net.shibboleth.oidc.security.jose.EncryptionParameters;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
 import net.shibboleth.oidc.security.jose.criterion.EncryptionConfigurationCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
-import net.shibboleth.oidc.security.jose.impl.BasicEncryptionConfiguration;
-import net.shibboleth.oidc.security.jose.impl.DefaultEncryptionParametersResolver;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
@@ -89,11 +90,34 @@ public class DefaultEncryptionParametersResolverTest {
 
         @Override
         protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
-            if (criteriaSet.contains(StaticCredentialCriterion.class)) {
-                final StaticCredentialCriterion credentialCriterion = 
-                        criteriaSet.get(StaticCredentialCriterion.class);
-                final Credential credential = credentialCriterion.getCredential();          
-                return List.of(credential);               
+            if (criteriaSet.contains(ClientSecretCredentialCriterion.class)) {
+                final ClientSecretCredentialCriterion credentialCriterion = 
+                        criteriaSet.get(ClientSecretCredentialCriterion.class);
+                final ClientSecretCredential credential = credentialCriterion.getCredential();          
+                return List.of(credential.toSigningCredential());               
+                
+            } else {
+                return Collections.emptyList();
+            }
+        }
+    
+    }
+    
+    /** Mock static credential resolver that is filterable.*/
+    private static class MockStaticCriteriaFilteringCredentialResolver_WrongKeyType 
+                                            extends AbstractCriteriaFilteringCredentialResolver
+        implements JOSEObjectCredentialResolver {
+
+
+        @Override
+        protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
+            if (criteriaSet.contains(ClientSecretCredentialCriterion.class)) {
+                final ClientSecretCredentialCriterion credentialCriterion = 
+                        criteriaSet.get(ClientSecretCredentialCriterion.class);
+                final ClientSecretCredential credential = credentialCriterion.getCredential();
+                
+                // Wrong key type for encryption
+                return List.of(credential.toSigningCredential());               
                 
             } else {
                 return Collections.emptyList();
@@ -148,8 +172,8 @@ public class DefaultEncryptionParametersResolverTest {
                 .keyID("mock-key-rsa")
                 .generate();
         creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
-        creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
 
         
         config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -180,10 +204,9 @@ public class DefaultEncryptionParametersResolverTest {
                 .keyID("mock-key-rsa")
                 .generate();
         creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
-        creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
 
-        
         config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
         
         final EncryptionParameters param = resolver.resolveSingle(criteria);
@@ -193,6 +216,7 @@ public class DefaultEncryptionParametersResolverTest {
        
     }
     
+    /* Generate a JWK with no 'alg', is optional and should generally match on the type.*/
     @Test
     public void testBasicRSA_NoAlgorithmSpecifiedInJWKCredential() throws Exception {
         final CriteriaSet criteria =  buildBasicCriteriaSet();
@@ -266,12 +290,11 @@ public class DefaultEncryptionParametersResolverTest {
                 .keyID("mock-key")
                 .generate();
         creds.add(TestCredentialHelper.createKeyAgreementCredential(key));
-        creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
-
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
         
         config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
-        
+
         final EncryptionParameters param = resolver.resolveSingle(criteria);
         
         assertNotNull(param);
@@ -292,10 +315,12 @@ public class DefaultEncryptionParametersResolverTest {
         config.setKeyTransportEncryptionAlgorithms(
                 List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));        
         
-        criteria.add(new StaticCredentialCriterion(TestCredentialHelper.createSharedSecretCredential("mock-key",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED)));
+        final List<Credential> creds = new ArrayList<>();
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
+
         
-        config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
+        config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
         
         final EncryptionParameters param = resolver.resolveSingle(criteria);
         
@@ -310,7 +335,7 @@ public class DefaultEncryptionParametersResolverTest {
        
     }
     
-    /* The key is 256bit and does not support the 128bit enc. algo.*/
+    /* The key is 256bit and does not support the 128bit enc. algo.*/    
     @Test
     public void testBasicAESKeyWrap_WrongKeyLength() throws Exception {
         final CriteriaSet criteria =  buildBasicCriteriaSet();
@@ -318,10 +343,13 @@ public class DefaultEncryptionParametersResolverTest {
                 List.of(KeyManagementConstants.ALGO_ID_ALG_AES_128_KW));        
         config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256));
         
-        criteria.add(new StaticCredentialCriterion(TestCredentialHelper.createSharedSecretCredential("mock-key",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED)));
+        final List<Credential> creds = new ArrayList<>();
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
+
         
-        config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
+        config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
+
         
         final EncryptionParameters param = resolver.resolveSingle(criteria);            
         assertNull(param);
@@ -340,8 +368,8 @@ public class DefaultEncryptionParametersResolverTest {
                 .keyID("mock-key-rsa")
                 .generate();
         creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
-        creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
 
         
         config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -374,8 +402,8 @@ public class DefaultEncryptionParametersResolverTest {
                 .keyID("mock-key-rsa")
                 .generate();
         creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
-        creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
 
         
         config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -408,8 +436,8 @@ public class DefaultEncryptionParametersResolverTest {
                 .keyID("mock-key-rsa")
                 .generate();
         creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
-        creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
 
         
         config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -426,92 +454,44 @@ public class DefaultEncryptionParametersResolverTest {
         assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
        
     }
-
-    @Test
-    public void testBasicAESKeyWrap_NoAlgorithmSpecifiedInJWKCredential() throws Exception {
-        final CriteriaSet criteria =  buildBasicCriteriaSet();
-        config.setKeyTransportEncryptionAlgorithms(
-                List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));  
-        
-        final JWKCredential cred = TestCredentialHelper.createSharedSecretCredential("mock-key",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED);
-        // Blank algorithm, this should work on the 'key algorithm' alone 
-        ((BasicJWKCredential)cred).setAlgorithm(null);
-        
-        criteria.add(new StaticCredentialCriterion(cred));
-        config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
-        final EncryptionParameters param = resolver.resolveSingle(criteria);
-        
-        assertNotNull(param);
-        assertNotNull(param.getDataEncryptionAlgorithm());
-        assertNotNull(param.getKeyTransportEncryptionAlgorithm());  
-        assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256);
-        assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_AES_256_KW);
-        assertNotNull(param.getKeyTransportEncryptionCredential());
-        assertNotNull(param.getKeyTransportEncryptionCredential().getSecretKey());
-        assertEquals(param.getKeyTransportEncryptionCredential().getSecretKey().getAlgorithm(),"AES");
-       
-    }
     
     @Test
-    public void testBasicAESKeyWrap_WrongUsageType() throws Exception {
+    public void testBasicAESKeyWrap_WrongKeyAndUsageType() throws Exception {
         final CriteriaSet criteria =  buildBasicCriteriaSet();
         config.setKeyTransportEncryptionAlgorithms(
-                List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));  
-        
-        final JWKCredential cred = TestCredentialHelper.createSharedSecretCredential("mock-key",
-                SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.SIGNING);
+                List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));          
         
-        criteria.add(new StaticCredentialCriterion(cred));
-        config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
+        criteria.add(
+                new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(SYMMETRIC_KEY)));
+        config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver_WrongKeyType());
         final EncryptionParameters param = resolver.resolveSingle(criteria);
         
         assertNull(param);
        
     }
     
-    @Test
-    public void testBasicAESKeyWrap_WrongCredentialAlgorithm() throws Exception {
-        final CriteriaSet criteria =  buildBasicCriteriaSet();
-        config.setKeyTransportEncryptionAlgorithms(
-                List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));  
-        
-        final RSAKey key = new RSAKeyGenerator(2048)
-                .algorithm(JWEAlgorithm.RSA_OAEP_256)
-                .keyUse(KeyUse.ENCRYPTION)
-                .keyID("mock-key")
-                .generate();
-        
-        criteria.add(new StaticCredentialCriterion(TestCredentialHelper.createKeyEncryptionCredential(key)));
-        
-        config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
-        final EncryptionParameters param = resolver.resolveSingle(criteria);
-        
-        assertNull(param);
-
-       
-    }
-    
     /* Direct encryption algorithm not supported at runtime.*/
     @Test(enabled=false)
     public void testBasicDirectEncryption() throws Exception {
         final CriteriaSet criteria =  buildBasicCriteriaSet();
         config.setKeyTransportEncryptionAlgorithms(
-                List.of(KeyManagementConstants.ALGO_ID_ALG_DIR));        
+                List.of(KeyManagementConstants.ALGO_ID_ALG_DIR));     
+        config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256,
+                EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
         
         final List<Credential> creds = new ArrayList<>();
-        creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
-                SYMMETRIC_KEY, JWEAlgorithm.DIR, UsageType.UNSPECIFIED));
+        creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+                .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256));
 
         
-        config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
+        config.setContentEncryptionKeyCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
         
         final EncryptionParameters param = resolver.resolveSingle(criteria);
         
         assertNotNull(param);
         assertNotNull(param.getDataEncryptionAlgorithm());
         assertNotNull(param.getKeyTransportEncryptionAlgorithm());  
-        assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+        assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256);
         assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_DIR);
         assertNotNull(param.getDataEncryptionCredential());
         assertNotNull(param.getDataEncryptionCredential().getSecretKey());
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
index 462dd34..3cb3f7b 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
@@ -74,9 +74,9 @@ import net.shibboleth.oidc.saml.xmlobject.Constants;
 import net.shibboleth.oidc.saml.xmlobject.DefaultAcrValue;
 import net.shibboleth.oidc.saml.xmlobject.MetadataValueSAMLObject;
 import net.shibboleth.oidc.saml.xmlobject.OAuthRPExtensions;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.credential.JWKReferenceCredential;
 import net.shibboleth.oidc.security.credential.NimbusSecretCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java
index 1ed00d5..4147740 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java
@@ -42,9 +42,9 @@ import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jose.jwk.KeyType;
 
 import net.shibboleth.oidc.saml.xmlobject.JwksData;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
 import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
 import net.shibboleth.utilities.java.support.codec.Base64Support;
 import net.shibboleth.utilities.java.support.codec.DecodingException;
 import net.shibboleth.utilities.java.support.collection.LazySet;
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
index 39f511a..6b1f6b0 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
@@ -31,12 +31,12 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.security.credential.Credential;
 
 import com.google.common.base.Predicates;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.profile.config.OverriddenIssuerProfileConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
@@ -102,16 +102,14 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
     /** An override to specify a specific redirect_uri to use over the normally computed one.*/
     @Nonnull private Function<ProfileRequestContext, String> redirectUriOverrideLookupStrategy;
 
-    /**
-     * Lookup function to retrieve the client_id from the given profile request context.
-     * Typically obtained from the issuer_id of the downstream relying-party (OP).
-     */
+    /** Lookup function to retrieve the client_id from the given profile request context.*/
+    //TODO this is the same as the issuer in the proxy context?
     @Nonnull private Function<ProfileRequestContext, String> clientIdLookupStrategy;
 
     /**
      * Lookup function to retrieve a client credential from the given profile request context.
      */
-    @Nonnull private Function<ProfileRequestContext, Credential> clientCredentialLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext, ClientSecretCredential> clientCredentialLookupStrategy;
 
     /** Lookup function to determine the client_authentication method.  */
     //TODO same as tokenEndpointAuthMethodsLookupStrategy?
@@ -441,7 +439,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
      * @param strategy the strategy to use
      */
     public void setClientCredentialLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, Credential> strategy) {
+            @Nonnull final Function<ProfileRequestContext, ClientSecretCredential> strategy) {
         clientCredentialLookupStrategy =
                 Constraint.isNotNull(strategy, "Client credential lookup strategy can not be null");
     }
@@ -451,7 +449,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
      *
      * @param clientCredential the static client credential to use
      */
-    public void setClientCredential(@Nullable final Credential clientCredential) {
+    public void setClientCredential(@Nullable final ClientSecretCredential clientCredential) {
         clientCredentialLookupStrategy = FunctionSupport.constant(clientCredential);
     }
 
@@ -463,7 +461,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
      *
      * @return the client credential
      */
-    public Credential getClientCredential(
+    public ClientSecretCredential getClientCredential(
             @Nullable final ProfileRequestContext profileRequestContext) {
         return clientCredentialLookupStrategy.apply(profileRequestContext);
     }
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java
index 12a2fac..2673f19 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java
@@ -43,7 +43,7 @@ import net.shibboleth.idp.profile.config.SecurityConfiguration;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.profile.config.JSONSecurityConfiguration;
 import net.shibboleth.oidc.profile.messaging.JSONSuccessResponse;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java
index 3566cc7..956c331 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java
@@ -27,20 +27,20 @@ import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
-import org.opensaml.security.credential.Credential;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.oidc.security.jose.DecryptionConfiguration;
 import net.shibboleth.oidc.security.jose.DecryptionParameters;
 import net.shibboleth.oidc.security.jose.DecryptionParametersResolver;
 import net.shibboleth.oidc.security.jose.EncryptionConfiguration;
 import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
 import net.shibboleth.oidc.security.jose.criterion.DecryptionConfigurationCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -150,7 +150,7 @@ public class PopulateJWTDecryptionParameters extends AbstractProfileAction {
             throw new ComponentInitializationException("DecryptionParametersResolver cannot be null");
         } 
         if (configurationLookupStrategy == null) {
-            throw new ComponentInitializationException("DecryptionConfiguraitonLookup cannot be null");
+            throw new ComponentInitializationException("DecryptionConfigurationLookup cannot be null");
         } 
     }
     
@@ -202,7 +202,7 @@ public class PopulateJWTDecryptionParameters extends AbstractProfileAction {
         final CriteriaSet criteria = new CriteriaSet();
         criteria.add(new DecryptionConfigurationCriterion(configs));
         
-        // Build a static credential criteria. Extract the decryption credential from the RP config.
+        // Build a client secret credential criteria. Extract the decryption credential from the RP config.
         final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);     
         if (rpCtx != null && rpCtx.getConfiguration() != null &&
                 rpCtx.getProfileConfig() instanceof OIDCAuthorizationConfiguration) {
@@ -210,9 +210,10 @@ public class PopulateJWTDecryptionParameters extends AbstractProfileAction {
                     (OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
             
             if (profileConfiguration != null) {
-                final Credential credential = profileConfiguration.getClientCredential(profileRequestContext);
+                final ClientSecretCredential credential = 
+                        profileConfiguration.getClientCredential(profileRequestContext);
                 if (credential != null) {
-                    criteria.add(new StaticCredentialCriterion(credential));
+                    criteria.add(new ClientSecretCredentialCriterion(credential));
                 } else {
                     log.trace("{} No credential found from the profile configuration", getLogPrefix());
                 }
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java
index fce324d..7659769 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java
@@ -29,27 +29,29 @@ import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
-import org.opensaml.security.credential.Credential;
 import org.opensaml.security.credential.UsageType;
 import org.opensaml.security.criteria.UsageCriterion;
 import org.opensaml.xmlsec.criterion.EncryptionOptionalCriterion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Predicates;
+
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
 import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
 import net.shibboleth.oidc.profile.config.logic.EncryptionOptionalPredicate;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.oidc.security.jose.EncryptionConfiguration;
 import net.shibboleth.oidc.security.jose.EncryptionParameters;
 import net.shibboleth.oidc.security.jose.EncryptionParametersResolver;
 import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
 import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
 import net.shibboleth.oidc.security.jose.criterion.EncryptionConfigurationCriterion;
 import net.shibboleth.oidc.security.jose.criterion.ProviderMetadataCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -226,6 +228,16 @@ public class PopulateJWTEncryptionParameters extends AbstractProfileAction {
         
         encryptionOptionalPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
     }
+    
+    /**
+     * Sets the boolean condition to apply to determine how to proceed if encryption parameter resolution fails.
+     * 
+     * @param flag the flag to set
+     */
+    public void setEncryptionOptional(@Nonnull final boolean flag) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);        
+        encryptionOptionalPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+    }
 
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -273,14 +285,12 @@ public class PopulateJWTEncryptionParameters extends AbstractProfileAction {
             if (params != null) {
                 log.debug("{} Resolved EncryptionParameters for {}", getLogPrefix(),forFriendlyName);
                 encryptionContext.setEncryptionParameters(params);          
-            } else {               
-                if (encryptionOptional) {
-                    log.debug("{} Resolver returned no EncryptionParameters", getLogPrefix());
-                    log.debug("{} Encryption is optional, ignoring inability to encrypt", getLogPrefix());
-                } else {
-                    log.warn("{} Resolver returned no EncryptionParameters", getLogPrefix());
-                    ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
-                }
+            } else if (encryptionOptional) {
+                log.debug("{} Resolver returned no EncryptionParameters", getLogPrefix());
+                log.debug("{} Encryption is optional, ignoring inability to encrypt", getLogPrefix());
+            } else {
+                log.warn("{} Resolver returned no EncryptionParameters", getLogPrefix());
+                ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
             }
         } catch (final ResolverException e) {
             if (encryptionOptional) {
@@ -341,11 +351,14 @@ public class PopulateJWTEncryptionParameters extends AbstractProfileAction {
                     (OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
             
             if (profileConfiguration != null) {
-                final Credential credential = profileConfiguration.getClientCredential(profileRequestContext);
+                final ClientSecretCredential credential = 
+                        profileConfiguration.getClientCredential(profileRequestContext);
                 if (credential != null) {
-                    criteria.add(new StaticCredentialCriterion(credential));
+                    criteria.add(new ClientSecretCredentialCriterion(credential));
+                    log.debug("{} Adding client_secret credential to resolution criteria",
+                            getLogPrefix());
                 } else {
-                    log.trace("{} No credential found from the profile configuration", getLogPrefix());
+                    log.trace("{} No client_secret credential found from the profile configuration", getLogPrefix());
                 }
             } else {
                 log.trace("{} Profile configuration not available, "
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java
index bb2a07c..2f7c575 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java
@@ -32,7 +32,6 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
 import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
 import org.opensaml.saml.criterion.RoleDescriptorCriterion;
-import org.opensaml.security.credential.Credential;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,6 +39,7 @@ import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
 import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.oidc.security.jose.SignatureSigningConfiguration;
 import net.shibboleth.oidc.security.jose.SignatureSigningParameters;
 import net.shibboleth.oidc.security.jose.SignatureSigningParametersResolver;
@@ -47,7 +47,7 @@ import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
 import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
 import net.shibboleth.oidc.security.jose.criterion.ProviderMetadataCriterion;
 import net.shibboleth.oidc.security.jose.criterion.SignatureSigningConfigurationCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -312,7 +312,7 @@ public class PopulateJWTSignatureSigningParametersHandler extends AbstractMessag
         }
         
         if (messageContext.getParent() instanceof ProfileRequestContext) {
-            // Add any static credentials from the RP context
+            // Add any static client secret credentials from the RP context
             final RelyingPartyContext rpCtx = 
                     relyingPartyContextLookupStrategy.apply(messageContext);     
             if (rpCtx != null && rpCtx.getConfiguration() != null &&
@@ -321,10 +321,10 @@ public class PopulateJWTSignatureSigningParametersHandler extends AbstractMessag
                         (OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
                 
                 if (profileConfiguration != null) {
-                    final Credential credential = profileConfiguration.getClientCredential(
+                    final ClientSecretCredential credential = profileConfiguration.getClientCredential(
                             (ProfileRequestContext)messageContext.getParent());
                     if (credential != null) {
-                        criteria.add(new StaticCredentialCriterion(credential));
+                        criteria.add(new ClientSecretCredentialCriterion(credential));
                     } else {
                         log.trace("{} No credential found from the profile configuration", getLogPrefix());
                     }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list