diff --git a/core/pom.xml b/core/pom.xml
index 5754ce3d849..3efc75aca77 100755
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -56,6 +56,12 @@
junit
test
+
+ com.nimbusds
+ nimbus-jose-jwt
+ 3.9
+ test
+
diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index 07071ffa635..5aba901df5c 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -25,6 +25,10 @@ public interface OAuth2Constants {
String REFRESH_TOKEN = "refresh_token";
+ String AUTHORIZATION_CODE = "authorization_code";
+
+ String PASSWORD = "password";
+
}
diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWK.java b/core/src/main/java/org/keycloak/jose/jwk/JWK.java
new file mode 100644
index 00000000000..d292f419777
--- /dev/null
+++ b/core/src/main/java/org/keycloak/jose/jwk/JWK.java
@@ -0,0 +1,62 @@
+package org.keycloak.jose.jwk;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class JWK {
+
+ public static final String KEY_ID = "kid";
+
+ public static final String KEY_TYPE = "kty";
+
+ public static final String ALGORITHM = "alg";
+
+ public static final String PUBLIC_KEY_USE = "use";
+
+ @JsonProperty(KEY_ID)
+ private String keyId;
+
+ @JsonProperty(KEY_TYPE)
+ private String keyType;
+
+ @JsonProperty(ALGORITHM)
+ private String algorithm;
+
+ @JsonProperty(PUBLIC_KEY_USE)
+ private String publicKeyUse;
+
+ public String getKeyId() {
+ return keyId;
+ }
+
+ public void setKeyId(String keyId) {
+ this.keyId = keyId;
+ }
+
+ public String getKeyType() {
+ return keyType;
+ }
+
+ public void setKeyType(String keyType) {
+ this.keyType = keyType;
+ }
+
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ public void setAlgorithm(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ public String getPublicKeyUse() {
+ return publicKeyUse;
+ }
+
+ public void setPublicKeyUse(String publicKeyUse) {
+ this.publicKeyUse = publicKeyUse;
+ }
+
+}
diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWKBuilder.java b/core/src/main/java/org/keycloak/jose/jwk/JWKBuilder.java
new file mode 100644
index 00000000000..bc3a228e51f
--- /dev/null
+++ b/core/src/main/java/org/keycloak/jose/jwk/JWKBuilder.java
@@ -0,0 +1,79 @@
+package org.keycloak.jose.jwk;
+
+import org.keycloak.util.Base64Url;
+
+import java.math.BigInteger;
+import java.security.Key;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class JWKBuilder {
+
+ public static final String DEFAULT_PUBLIC_KEY_USE = "sig";
+ public static final String DEFAULT_MESSAGE_DIGEST = "SHA-256";
+
+
+ private JWKBuilder() {
+ }
+
+ public static JWKBuilder create() {
+ return new JWKBuilder();
+ }
+
+ public JWK rs256(PublicKey key) {
+ RSAPublicKey rsaKey = (RSAPublicKey) key;
+
+ RSAPublicJWK k = new RSAPublicJWK();
+ k.setKeyId(createKeyId(key));
+ k.setKeyType(RSAPublicJWK.RSA);
+ k.setAlgorithm(RSAPublicJWK.RS256);
+ k.setPublicKeyUse(DEFAULT_PUBLIC_KEY_USE);
+ k.setModulus(Base64Url.encode(toIntegerBytes(rsaKey.getModulus())));
+ k.setPublicExponent(Base64Url.encode(toIntegerBytes(rsaKey.getPublicExponent())));
+
+ return k;
+ }
+
+ private String createKeyId(Key key) {
+ try {
+ return Base64Url.encode(MessageDigest.getInstance(DEFAULT_MESSAGE_DIGEST).digest(key.getEncoded()));
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copied from org.apache.commons.codec.binary.Base64
+ */
+ private static byte[] toIntegerBytes(final BigInteger bigInt) {
+ int bitlen = bigInt.bitLength();
+ // round bitlen
+ bitlen = ((bitlen + 7) >> 3) << 3;
+ final byte[] bigBytes = bigInt.toByteArray();
+
+ if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
+ return bigBytes;
+ }
+ // set up params for copying everything but sign bit
+ int startSrc = 0;
+ int len = bigBytes.length;
+
+ // if bigInt is exactly byte-aligned, just skip signbit in copy
+ if ((bigInt.bitLength() % 8) == 0) {
+ startSrc = 1;
+ len--;
+ }
+ final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
+ final byte[] resizedBytes = new byte[bitlen / 8];
+ System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
+ return resizedBytes;
+ }
+
+}
diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
new file mode 100644
index 00000000000..38f02d83cbf
--- /dev/null
+++ b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
@@ -0,0 +1,54 @@
+package org.keycloak.jose.jwk;
+
+import org.codehaus.jackson.type.TypeReference;
+import org.keycloak.util.Base64Url;
+import org.keycloak.util.JsonSerialization;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Map;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class JWKParser {
+
+ private static TypeReference