keycloak-uncached
Changes
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java 13(+7 -6)
integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java 23(+21 -2)
integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java 34(+16 -18)
services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java 13(+3 -10)
services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java 9(+3 -6)
services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java 3(+2 -1)
services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java 47(+26 -21)
services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java 47(+39 -8)
services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationUriUtils.java 7(+7 -0)
services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java 2(+2 -0)
Details
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
index ddd1152..78d98e7 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
@@ -43,6 +43,7 @@ import org.keycloak.common.VerificationException;
 import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
 import org.keycloak.constants.ServiceUrlConstants;
 import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 import org.keycloak.util.JsonSerialization;
 import org.keycloak.common.util.KeycloakUriBuilder;
 
@@ -102,9 +103,9 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
             StringBuilder errorBuilder = new StringBuilder("Login failed. Invalid status: " + status);
             if (entity != null) {
                 InputStream is = entity.getContent();
-                Map<String, String> errors = (Map<String, String>) JsonSerialization.readValue(is, Map.class);
-                errorBuilder.append(", OAuth2 error. Error: " + errors.get(OAuth2Constants.ERROR))
-                        .append(", Error description: " + errors.get(OAuth2Constants.ERROR_DESCRIPTION));
+                OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(is, OAuth2ErrorRepresentation.class);
+                errorBuilder.append(", OAuth2 error. Error: " + errorRep.getError())
+                        .append(", Error description: " + errorRep.getErrorDescription());
             }
             String error = errorBuilder.toString();
             log.warn(error);
@@ -161,9 +162,9 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
                     if (entity != null) {
                         InputStream is = entity.getContent();
                         if (status == 400) {
-                            Map<String, String> errors = (Map<String, String>) JsonSerialization.readValue(is, Map.class);
-                            errorBuilder.append(", OAuth2 error. Error: " + errors.get(OAuth2Constants.ERROR))
-                                    .append(", Error description: " + errors.get(OAuth2Constants.ERROR_DESCRIPTION));
+                            OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(is, OAuth2ErrorRepresentation.class);
+                            errorBuilder.append(", OAuth2 error. Error: " + errorRep.getError())
+                                    .append(", Error description: " + errorRep.getErrorDescription());
 
                         } else {
                             if (is != null) is.close();
                diff --git a/core/src/main/java/org/keycloak/OAuthErrorException.java b/core/src/main/java/org/keycloak/OAuthErrorException.java
index f0bb862..940d434 100755
--- a/core/src/main/java/org/keycloak/OAuthErrorException.java
+++ b/core/src/main/java/org/keycloak/OAuthErrorException.java
@@ -37,12 +37,18 @@ public class OAuthErrorException extends Exception {
     public static final String REQUEST_NOT_SUPPORTED = "request_not_supported";
     public static final String REQUEST_URI_NOT_SUPPORTED = "request_uri_not_supported";
 
+    // OAuth2 Bearer Token Usage
+    public static final String INVALID_TOKEN = "invalid_token";
+    public static final String INSUFFICIENT_SCOPE = "insufficient_scope";
+
+    // OIDC Dynamic Client Registration
+    public static final String INVALID_REDIRECT_URI = "invalid_redirect_uri";
+    public static final String INVALID_CLIENT_METADATA = "invalid_client_metadata";
+
     // Others
     public static final String INVALID_CLIENT = "invalid_client";
     public static final String INVALID_GRANT = "invalid_grant";
     public static final String UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type";
-    public static final String INVALID_TOKEN = "invalid_token";
-    public static final String INSUFFICIENT_SCOPE = "insufficient_scope";
 
     public OAuthErrorException(String error, String description, String message, Throwable cause) {
         super(message, cause);
                diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuth2ErrorRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuth2ErrorRepresentation.java
new file mode 100644
index 0000000..f988013
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/OAuth2ErrorRepresentation.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.keycloak.OAuth2Constants;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OAuth2ErrorRepresentation {
+
+    private String error;
+    private String errorDescription;
+
+    public OAuth2ErrorRepresentation() {
+    }
+
+    public OAuth2ErrorRepresentation(String error, String errorDescription) {
+        this.error = error;
+        this.errorDescription = errorDescription;
+    }
+
+    @JsonProperty(OAuth2Constants.ERROR)
+    public String getError() {
+        return error;
+    }
+
+    public void setError(String error) {
+        this.error = error;
+    }
+
+    @JsonProperty(OAuth2Constants.ERROR_DESCRIPTION)
+    public String getErrorDescription() {
+        return errorDescription;
+    }
+
+    public void setErrorDescription(String errorDescription) {
+        this.errorDescription = errorDescription;
+    }
+}
                diff --git a/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java b/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
index fc2973d..26082db 100644
--- a/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
@@ -27,14 +27,20 @@ import java.util.List;
 @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
 public class OIDCClientRepresentation {
 
+    // OIDC Dynamic client registration properties
+
     private List<String> redirect_uris;
 
     private String token_endpoint_auth_method;
 
+    private String token_endpoint_auth_signing_alg;
+
     private List<String> grant_types;
 
     private List<String> response_types;
 
+    private String application_type;
+
     private String client_id;
 
     private String client_secret;
@@ -47,7 +53,7 @@ public class OIDCClientRepresentation {
 
     private String scope;
 
-    private String contacts;
+    private List<String> contacts;
 
     private String tos_uri;
 
@@ -57,10 +63,47 @@ public class OIDCClientRepresentation {
 
     private String jwks;
 
+    private String sector_identifier_uri;
+
+    private String subject_type;
+
+    private String id_token_signed_response_alg;
+
+    private String id_token_encrypted_response_alg;
+
+    private String id_token_encrypted_response_enc;
+
+    private String userinfo_signed_response_alg;
+
+    private String userinfo_encrypted_response_alg;
+
+    private String userinfo_encrypted_response_enc;
+
+    private String request_object_signing_alg;
+
+    private String request_object_encryption_alg;
+
+    private String request_object_encryption_enc;
+
+    private Integer default_max_age;
+
+    private Boolean require_auth_time;
+
+    private List<String> default_acr_values;
+
+    private String initiate_login_uri;
+
+    private List<String> request_uris;
+
+    // OIDC Session Management
+    private List<String> post_logout_redirect_uris;
+
+    // Not sure from which specs this comes
     private String software_id;
 
     private String software_version;
 
+    // OIDC Dynamic Client Registration Response
     private Integer client_id_issued_at;
 
     private Integer client_secret_expires_at;
@@ -85,6 +128,14 @@ public class OIDCClientRepresentation {
         this.token_endpoint_auth_method = token_endpoint_auth_method;
     }
 
+    public String getTokenEndpointAuthSigningAlg() {
+        return token_endpoint_auth_signing_alg;
+    }
+
+    public void setTokenEndpointAuthSigningAlg(String token_endpoint_auth_signing_alg) {
+        this.token_endpoint_auth_signing_alg = token_endpoint_auth_signing_alg;
+    }
+
     public List<String> getGrantTypes() {
         return grant_types;
     }
@@ -101,6 +152,14 @@ public class OIDCClientRepresentation {
         this.response_types = responseTypes;
     }
 
+    public String getApplicationType() {
+        return application_type;
+    }
+
+    public void setApplicationType(String applicationType) {
+        this.application_type = applicationType;
+    }
+
     public String getClientId() {
         return client_id;
     }
@@ -149,11 +208,11 @@ public class OIDCClientRepresentation {
         this.scope = scope;
     }
 
-    public String getContacts() {
+    public List<String> getContacts() {
         return contacts;
     }
 
-    public void setContacts(String contacts) {
+    public void setContacts(List<String> contacts) {
         this.contacts = contacts;
     }
 
@@ -189,6 +248,142 @@ public class OIDCClientRepresentation {
         this.jwks = jwks;
     }
 
+    public String getSectorIdentifierUri() {
+        return sector_identifier_uri;
+    }
+
+    public void setSectorIdentifierUri(String sectorIdentifierUri) {
+        this.sector_identifier_uri = sectorIdentifierUri;
+    }
+
+    public String getSubjectType() {
+        return subject_type;
+    }
+
+    public void setSubjectType(String subjectType) {
+        this.subject_type = subjectType;
+    }
+
+    public String getIdTokenSignedResponseAlg() {
+        return id_token_signed_response_alg;
+    }
+
+    public void setIdTokenSignedResponseAlg(String idTokenSignedResponseAlg) {
+        this.id_token_signed_response_alg = idTokenSignedResponseAlg;
+    }
+
+    public String getIdTokenEncryptedResponseAlg() {
+        return id_token_encrypted_response_alg;
+    }
+
+    public void setIdTokenEncryptedResponseAlg(String idTokenEncryptedResponseAlg) {
+        this.id_token_encrypted_response_alg = idTokenEncryptedResponseAlg;
+    }
+
+    public String getIdTokenEncryptedResponseEnc() {
+        return id_token_encrypted_response_enc;
+    }
+
+    public void setIdTokenEncryptedResponseEnc(String idTokenEncryptedResponseEnc) {
+        this.id_token_encrypted_response_enc = idTokenEncryptedResponseEnc;
+    }
+
+    public String getUserinfoSignedResponseAlg() {
+        return userinfo_signed_response_alg;
+    }
+
+    public void setUserinfoSignedResponseAlg(String userinfo_signed_response_alg) {
+        this.userinfo_signed_response_alg = userinfo_signed_response_alg;
+    }
+
+    public String getUserinfoEncryptedResponseAlg() {
+        return userinfo_encrypted_response_alg;
+    }
+
+    public void setUserinfoEncryptedResponseAlg(String userinfo_encrypted_response_alg) {
+        this.userinfo_encrypted_response_alg = userinfo_encrypted_response_alg;
+    }
+
+    public String getUserinfoEncryptedResponseEnc() {
+        return userinfo_encrypted_response_enc;
+    }
+
+    public void setUserinfoEncryptedResponseEnc(String userinfo_encrypted_response_enc) {
+        this.userinfo_encrypted_response_enc = userinfo_encrypted_response_enc;
+    }
+
+    public String getRequestObjectSigningAlg() {
+        return request_object_signing_alg;
+    }
+
+    public void setRequestObjectSigningAlg(String request_object_signing_alg) {
+        this.request_object_signing_alg = request_object_signing_alg;
+    }
+
+    public String getRequestObjectEncryptionAlg() {
+        return request_object_encryption_alg;
+    }
+
+    public void setRequestObjectEncryptionAlg(String request_object_encryption_alg) {
+        this.request_object_encryption_alg = request_object_encryption_alg;
+    }
+
+    public String getRequestObjectEncryptionEnc() {
+        return request_object_encryption_enc;
+    }
+
+    public void setRequestObjectEncryptionEnc(String request_object_encryption_enc) {
+        this.request_object_encryption_enc = request_object_encryption_enc;
+    }
+
+    public Integer getDefaultMaxAge() {
+        return default_max_age;
+    }
+
+    public void setDefaultMaxAge(Integer default_max_age) {
+        this.default_max_age = default_max_age;
+    }
+
+    public Boolean getRequireAuthTime() {
+        return require_auth_time;
+    }
+
+    public void setRequireAuthTime(Boolean require_auth_time) {
+        this.require_auth_time = require_auth_time;
+    }
+
+    public List<String> getDefaultAcrValues() {
+        return default_acr_values;
+    }
+
+    public void setDefaultAcrValues(List<String> default_acr_values) {
+        this.default_acr_values = default_acr_values;
+    }
+
+    public String getInitiateLoginUri() {
+        return initiate_login_uri;
+    }
+
+    public void setInitiateLoginUri(String initiate_login_uri) {
+        this.initiate_login_uri = initiate_login_uri;
+    }
+
+    public List<String> getRequestUris() {
+        return request_uris;
+    }
+
+    public void setRequestUris(List<String> requestUris) {
+        this.request_uris = requestUris;
+    }
+
+    public List<String> getPostLogoutRedirectUris() {
+        return post_logout_redirect_uris;
+    }
+
+    public void setPostLogoutRedirectUris(List<String> post_logout_redirect_uris) {
+        this.post_logout_redirect_uris = post_logout_redirect_uris;
+    }
+
     public String getSoftwareId() {
         return software_id;
     }
                diff --git a/core/src/test/java/org/keycloak/JsonParserTest.java b/core/src/test/java/org/keycloak/JsonParserTest.java
index 69416b7..062dc9b 100755
--- a/core/src/test/java/org/keycloak/JsonParserTest.java
+++ b/core/src/test/java/org/keycloak/JsonParserTest.java
@@ -33,6 +33,7 @@ import org.junit.Test;
 import org.keycloak.representations.IDToken;
 import org.keycloak.representations.JsonWebToken;
 import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.representations.oidc.OIDCClientRepresentation;
 import org.keycloak.util.JsonSerialization;
 
 /**
@@ -125,4 +126,15 @@ public class JsonParserTest {
         System.out.println(sb.toString());
     }
 
+    @Test
+    public void testReadOIDCClientRep() throws IOException {
+        String stringRep = "{\"subject_type\": \"public\", \"jwks_uri\": \"https://op.certification.openid.net:60720/export/jwk_60720.json\", \"contacts\": [\"roland.hedberg@umu.se\"], \"application_type\": \"web\", \"grant_types\": [\"authorization_code\"], \"post_logout_redirect_uris\": [\"https://op.certification.openid.net:60720/logout\"], \"redirect_uris\": [\"https://op.certification.openid.net:60720/authz_cb\"], \"response_types\": [\"code\"], \"require_auth_time\": true, \"default_max_age\": 3600}";
+        OIDCClientRepresentation clientRep = JsonSerialization.readValue(stringRep, OIDCClientRepresentation.class);
+        Assert.assertEquals("public", clientRep.getSubjectType());
+        Assert.assertTrue(clientRep.getRequireAuthTime());
+        Assert.assertEquals(3600, clientRep.getDefaultMaxAge().intValue());
+        Assert.assertEquals(1, clientRep.getRedirectUris().size());
+        Assert.assertEquals("https://op.certification.openid.net:60720/authz_cb", clientRep.getRedirectUris().get(0));
+    }
+
 }
                diff --git a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java
index 4078b73..640bc0d 100644
--- a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java
+++ b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java
@@ -18,6 +18,8 @@
 package org.keycloak.client.registration;
 
 import org.apache.http.StatusLine;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
+import org.keycloak.util.JsonSerialization;
 
 import java.io.IOException;
 
@@ -26,14 +28,31 @@ import java.io.IOException;
  */
 public class HttpErrorException extends IOException {
 
-    private StatusLine statusLine;
+    private final StatusLine statusLine;
+    private final String errorResponse;
 
-    public HttpErrorException(StatusLine statusLine) {
+    public HttpErrorException(StatusLine statusLine, String errorResponse) {
         this.statusLine = statusLine;
+        this.errorResponse = errorResponse;
     }
 
     public StatusLine getStatusLine() {
         return statusLine;
     }
 
+    public String getErrorResponse() {
+        return errorResponse;
+    }
+
+    public OAuth2ErrorRepresentation toErrorRepresentation() {
+        if (errorResponse == null) {
+            return null;
+        }
+
+        try {
+            return JsonSerialization.readValue(errorResponse, OAuth2ErrorRepresentation.class);
+        } catch (IOException ioe) {
+            throw new RuntimeException("Not OAuth2 error");
+        }
+    }
 }
                diff --git a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java
index 8d524ce..66808ed 100644
--- a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java
+++ b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java
@@ -23,9 +23,7 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.*;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
-import org.keycloak.client.registration.Auth;
-import org.keycloak.client.registration.ClientRegistrationException;
-import org.keycloak.client.registration.HttpErrorException;
+import org.keycloak.common.util.StreamUtil;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -69,8 +67,7 @@ class HttpUtil {
             if (response.getStatusLine().getStatusCode() == 201) {
                 return responseStream;
             } else {
-                responseStream.close();
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -97,10 +94,7 @@ class HttpUtil {
                 responseStream.close();
                 return null;
             } else {
-                if (responseStream != null) {
-                    responseStream.close();
-                }
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -118,9 +112,6 @@ class HttpUtil {
             addAuth(request);
 
             HttpResponse response = httpClient.execute(request);
-            if (response.getEntity() != null) {
-                response.getEntity().getContent();
-            }
 
             InputStream responseStream = null;
             if (response.getEntity() != null) {
@@ -130,10 +121,7 @@ class HttpUtil {
             if (response.getStatusLine().getStatusCode() == 200) {
                 return responseStream;
             } else {
-                if (responseStream != null) {
-                    responseStream.close();
-                }
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -147,12 +135,13 @@ class HttpUtil {
             addAuth(request);
 
             HttpResponse response = httpClient.execute(request);
+            InputStream responseStream = null;
             if (response.getEntity() != null) {
-                response.getEntity().getContent().close();
+                responseStream = response.getEntity().getContent();
             }
 
             if (response.getStatusLine().getStatusCode() != 204) {
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -185,4 +174,13 @@ class HttpUtil {
         }
     }
 
+    private HttpErrorException httpErrorException(HttpResponse response, InputStream responseStream) throws IOException {
+        if (responseStream != null) {
+            String errorResponse = StreamUtil.readString(responseStream);
+            return new HttpErrorException(response.getStatusLine(), errorResponse);
+        } else {
+            return new HttpErrorException(response.getStatusLine(), null);
+        }
+    }
+
 }
                diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java
index 0d7d911..94cefa3 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java
@@ -17,13 +17,10 @@
 
 package org.keycloak.authentication.authenticators.client;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import org.keycloak.OAuth2Constants;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -32,12 +29,8 @@ public class ClientAuthUtil {
 
 
     public static Response errorResponse(int status, String error, String errorDescription) {
-        Map<String, String> e = new HashMap<String, String>();
-        e.put(OAuth2Constants.ERROR, error);
-        if (errorDescription != null) {
-            e.put(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
-        }
-        return Response.status(status).entity(e).type(MediaType.APPLICATION_JSON_TYPE).build();
+        OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription);
+        return Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build();
     }
 
 }
                diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java
index 8de4230..88d0e15 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java
@@ -24,6 +24,7 @@ import org.keycloak.authentication.Authenticator;
 import org.keycloak.authentication.AuthenticatorFactory;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -36,12 +37,8 @@ import java.util.Map;
  */
 public abstract class AbstractDirectGrantAuthenticator implements Authenticator, AuthenticatorFactory {
     public Response errorResponse(int status, String error, String errorDescription) {
-        Map<String, String> e = new HashMap<String, String>();
-        e.put(OAuth2Constants.ERROR, error);
-        if (errorDescription != null) {
-            e.put(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
-        }
-        return Response.status(status).entity(e).type(MediaType.APPLICATION_JSON_TYPE).build();
+        OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription);
+        return Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build();
     }
 
     @Override
                diff --git a/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
index ffda262..87fab80 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
@@ -54,8 +54,9 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
 
             client = ModelToRepresentation.toRepresentation(clientModel);
 
-            String registrationAccessToken = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, clientModel);
+            client.setSecret(clientModel.getSecret());
 
+            String registrationAccessToken = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, clientModel);
             client.setRegistrationAccessToken(registrationAccessToken);
 
             if (auth.isInitialAccessToken()) {
                diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
index 5564ef2..7886cf8 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
@@ -21,8 +21,10 @@ import org.jboss.resteasy.spi.Failure;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.UnauthorizedException;
 import org.keycloak.Config;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.common.util.Time;
+import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.AdminRoles;
@@ -33,7 +35,9 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
 import org.keycloak.representations.JsonWebToken;
+import org.keycloak.services.ErrorResponseException;
 import org.keycloak.services.ForbiddenException;
+import org.keycloak.services.ServicesLogger;
 import org.keycloak.util.TokenUtil;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -65,23 +69,24 @@ public class ClientRegistrationAuth {
 
         String authorizationHeader = session.getContext().getRequestHeaders().getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
         if (authorizationHeader == null) {
-            return;
+            throw unauthorized("Missing Authorization header");
         }
 
         String[] split = authorizationHeader.split(" ");
         if (!split[0].equalsIgnoreCase("bearer")) {
-            return;
+            throw unauthorized("Invalid Authorization header. Expected type: Bearer");
         }
 
-        jwt = ClientRegistrationTokenUtils.verifyToken(realm, uri, split[1]);
-        if (jwt == null) {
-            throw unauthorized();
+        ClientRegistrationTokenUtils.TokenVerification tokenVerification = ClientRegistrationTokenUtils.verifyToken(realm, uri, split[1]);
+        if (tokenVerification.getError() != null) {
+            throw unauthorized(tokenVerification.getError().getMessage());
         }
+        jwt = tokenVerification.getJwt();
 
         if (isInitialAccessToken()) {
             initialAccessModel = session.sessions().getClientInitialAccessModel(session.getContext().getRealm(), jwt.getId());
             if (initialAccessModel == null) {
-                throw unauthorized();
+                throw unauthorized("Initial Access Token not found");
             }
         }
     }
@@ -115,7 +120,7 @@ public class ClientRegistrationAuth {
             }
         }
 
-        throw unauthorized();
+        throw unauthorized("Not authorized to view client. Maybe bad token type.");
     }
 
     public void requireView(ClientModel client) {
@@ -131,18 +136,18 @@ public class ClientRegistrationAuth {
                 throw forbidden();
             }
         } else if (isRegistrationAccessToken()) {
-            if (client.getRegistrationToken() != null && client != null && client.getRegistrationToken().equals(jwt.getId())) {
+            if (client.getRegistrationToken() != null && client.getRegistrationToken().equals(jwt.getId())) {
                 return;
             }
         } else if (isInitialAccessToken()) {
-            throw unauthorized();
+            throw unauthorized("Not initial access token");
         } else {
             if (authenticateClient(client)) {
                 return;
             }
         }
 
-        throw unauthorized();
+        throw unauthorized("Not authorized to view client. Maybe bad token type.");
     }
 
     public void requireUpdate(ClientModel client) {
@@ -163,7 +168,7 @@ public class ClientRegistrationAuth {
             }
         }
 
-        throw unauthorized();
+        throw unauthorized("Not authorized to update client. Maybe bad token type.");
     }
 
     public ClientInitialAccessModel getInitialAccessModel() {
@@ -218,36 +223,36 @@ public class ClientRegistrationAuth {
         Response response = processor.authenticateClient();
         if (response != null) {
             event.client(client.getClientId()).error(Errors.NOT_ALLOWED);
-            throw unauthorized();
+            throw unauthorized("Failed to authenticate client");
         }
 
         ClientModel authClient = processor.getClient();
-        if (client == null) {
+        if (authClient == null) {
             event.client(client.getClientId()).error(Errors.NOT_ALLOWED);
-            throw unauthorized();
+            throw unauthorized("No client authenticated");
         }
 
         if (!authClient.getClientId().equals(client.getClientId())) {
             event.client(client.getClientId()).error(Errors.NOT_ALLOWED);
-            throw unauthorized();
+            throw unauthorized("Different client authenticated");
         }
 
         return true;
     }
 
-    private Failure unauthorized() {
-        event.error(Errors.NOT_ALLOWED);
-        return new UnauthorizedException();
+    private Failure unauthorized(String errorDescription) {
+        event.detail(Details.REASON, errorDescription).error(Errors.INVALID_TOKEN);
+        throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, errorDescription, Response.Status.UNAUTHORIZED);
     }
 
     private Failure forbidden() {
         event.error(Errors.NOT_ALLOWED);
-        return new ForbiddenException();
+        throw new ErrorResponseException(OAuthErrorException.INSUFFICIENT_SCOPE, "Forbidden", Response.Status.FORBIDDEN);
     }
 
     private Failure notFound() {
-        event.error(Errors.NOT_ALLOWED);
-        return new NotFoundException("Client not found");
+        event.error(Errors.CLIENT_NOT_FOUND);
+        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client not found", Response.Status.NOT_FOUND);
     }
 
 }
                diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
index 2fe65cc..2f33e5d 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
@@ -56,40 +56,44 @@ public class ClientRegistrationTokenUtils {
         return createToken(realm, uri, model.getId(), TYPE_INITIAL_ACCESS_TOKEN, model.getExpiration() > 0 ? model.getTimestamp() + model.getExpiration() : 0);
     }
 
-    public static JsonWebToken verifyToken(RealmModel realm, UriInfo uri, String token) {
+    public static TokenVerification verifyToken(RealmModel realm, UriInfo uri, String token) {
+        if (token == null) {
+            return TokenVerification.error(new RuntimeException("Missing token"));
+        }
+
         JWSInput input;
         try {
             input = new JWSInput(token);
         } catch (JWSInputException e) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Invalid token", e));
         }
 
         if (!RSAProvider.verify(input, realm.getPublicKey())) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Failed verify token"));
         }
 
         JsonWebToken jwt;
         try {
             jwt = input.readJsonContent(JsonWebToken.class);
         } catch (JWSInputException e) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Token is not JWT", e));
         }
 
         if (!getIssuer(realm, uri).equals(jwt.getIssuer())) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Issuer from token don't match with the realm issuer."));
         }
 
         if (!jwt.isActive()) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Token not active."));
         }
 
         if (!(TokenUtil.TOKEN_TYPE_BEARER.equals(jwt.getType()) ||
                 TYPE_INITIAL_ACCESS_TOKEN.equals(jwt.getType()) ||
                 TYPE_REGISTRATION_ACCESS_TOKEN.equals(jwt.getType()))) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Invalid type of token"));
         }
 
-        return jwt;
+        return TokenVerification.success(jwt);
     }
 
     private static String createToken(RealmModel realm, UriInfo uri, String id, String type, int expiration) {
@@ -112,4 +116,31 @@ public class ClientRegistrationTokenUtils {
         return Urls.realmIssuer(uri.getBaseUri(), realm.getName());
     }
 
+    protected static class TokenVerification {
+
+        private final JsonWebToken jwt;
+        private final RuntimeException error;
+
+        public static TokenVerification success(JsonWebToken jwt) {
+            return new TokenVerification(jwt, null);
+        }
+
+        public static TokenVerification error(RuntimeException error) {
+            return new TokenVerification(null, error);
+        }
+
+        private TokenVerification(JsonWebToken jwt, RuntimeException error) {
+            this.jwt = jwt;
+            this.error = error;
+        }
+
+        public JsonWebToken getJwt() {
+            return jwt;
+        }
+
+        public RuntimeException getError() {
+            return error;
+        }
+    }
+
 }
                diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationUriUtils.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationUriUtils.java
new file mode 100644
index 0000000..3108003
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationUriUtils.java
@@ -0,0 +1,7 @@
+package org.keycloak.services.clientregistration;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegistrationUriUtils {
+}
                diff --git a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
index cfbf42d..b797282 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
@@ -66,6 +66,8 @@ public class DescriptionConverter {
     public static OIDCClientRepresentation toExternalResponse(ClientRepresentation client, URI uri) {
         OIDCClientRepresentation response = new OIDCClientRepresentation();
         response.setClientId(client.getClientId());
+        response.setClientSecret(client.getSecret());
+        response.setClientSecretExpiresAt(0);
         response.setClientName(client.getName());
         response.setClientUri(client.getBaseUrl());
         response.setClientSecret(client.getSecret());
                diff --git a/services/src/main/java/org/keycloak/services/ErrorResponseException.java b/services/src/main/java/org/keycloak/services/ErrorResponseException.java
index c29f0f3..538374c 100644
--- a/services/src/main/java/org/keycloak/services/ErrorResponseException.java
+++ b/services/src/main/java/org/keycloak/services/ErrorResponseException.java
@@ -18,6 +18,7 @@
 package org.keycloak.services;
 
 import org.keycloak.OAuth2Constants;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
@@ -42,12 +43,8 @@ public class ErrorResponseException extends WebApplicationException {
 
     @Override
     public Response getResponse() {
-        Map<String, String> e = new HashMap<String, String>();
-        e.put(OAuth2Constants.ERROR, error);
-        if (errorDescription != null) {
-            e.put(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
-        }
-        return Response.status(status).entity(e).type(MediaType.APPLICATION_JSON_TYPE).build();
+        OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription);
+        return Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build();
     }
 
 }
                diff --git a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
index c633587..898ad3c 100755
--- a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
+++ b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources;
 import org.jboss.resteasy.spi.BadRequestException;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.UnauthorizedException;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.constants.AdapterConstants;
@@ -30,6 +31,7 @@ import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 import org.keycloak.services.ForbiddenException;
 import org.keycloak.services.ServicesLogger;
 import org.keycloak.common.util.Time;
@@ -172,11 +174,9 @@ public class ClientsManagementService {
         ClientModel client = AuthorizeClientUtil.authorizeClient(session, event).getClient();
 
         if (client.isPublicClient()) {
-            Map<String, String> error = new HashMap<String, String>();
-            error.put(OAuth2Constants.ERROR, "invalid_client");
-            error.put(OAuth2Constants.ERROR_DESCRIPTION, "Public clients not allowed");
+            OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(OAuthErrorException.INVALID_CLIENT, "Public clients not allowed");
             event.error(Errors.INVALID_CLIENT);
-            throw new BadRequestException("Public clients not allowed", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(error).type(MediaType.APPLICATION_JSON_TYPE).build());
+            throw new BadRequestException("Public clients not allowed", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build());
         }
 
         return client;
@@ -185,11 +185,9 @@ public class ClientsManagementService {
     protected String getClientClusterHost(MultivaluedMap<String, String> formData) {
         String clientClusterHost = formData.getFirst(AdapterConstants.CLIENT_CLUSTER_HOST);
         if (clientClusterHost == null || clientClusterHost.length() == 0) {
-            Map<String, String> error = new HashMap<String, String>();
-            error.put(OAuth2Constants.ERROR, "invalid_request");
-            error.put(OAuth2Constants.ERROR_DESCRIPTION, "Client cluster host not specified");
+            OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation( OAuthErrorException.INVALID_REQUEST, "Client cluster host not specified");
             event.error(Errors.INVALID_CODE);
-            throw new BadRequestException("Cluster host not specified", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(error).type(MediaType.APPLICATION_JSON_TYPE).build());
+            throw new BadRequestException("Cluster host not specified", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build());
         }
 
         return clientClusterHost;
                diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
index ab587c3..9b364e8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
@@ -20,13 +20,17 @@ package org.keycloak.testsuite.client;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.client.registration.Auth;
 import org.keycloak.client.registration.ClientRegistrationException;
+import org.keycloak.client.registration.HttpErrorException;
 import org.keycloak.common.util.CollectionUtil;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
 import org.keycloak.representations.idm.ClientInitialAccessPresentation;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 import org.keycloak.representations.oidc.OIDCClientRepresentation;
+import org.keycloak.testsuite.Assert;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -58,13 +62,33 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
     }
 
     @Test
+    public void testMissingToken() throws Exception {
+        reg.auth(null);
+
+        OIDCClientRepresentation client = new OIDCClientRepresentation();
+        client.setClientName("RegistrationAccessTokenTest");
+        client.setClientUri("http://root");
+        client.setRedirectUris(Collections.singletonList("http://redirect"));
+
+        try {
+            reg.oidc().create(client);
+            Assert.fail("Not expected to successfuly register client");
+        } catch (ClientRegistrationException expected) {
+            HttpErrorException httpEx = (HttpErrorException) expected.getCause();
+            Assert.assertEquals(401, httpEx.getStatusLine().getStatusCode());
+            Assert.assertEquals(OAuthErrorException.INVALID_TOKEN, httpEx.toErrorRepresentation().getError());
+        }
+    }
+
+    @Test
     public void createClient() throws ClientRegistrationException {
         OIDCClientRepresentation response = create();
 
         assertNotNull(response.getRegistrationAccessToken());
         assertNotNull(response.getClientIdIssuedAt());
         assertNotNull(response.getClientId());
-        assertNull(response.getClientSecretExpiresAt());
+        assertNotNull(response.getClientSecret());
+        assertEquals(0, response.getClientSecretExpiresAt().intValue());
         assertNotNull(response.getRegistrationClientUri());
         assertEquals("RegistrationAccessTokenTest", response.getClientName());
         assertEquals("http://root", response.getClientUri());
@@ -84,6 +108,8 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         assertNotEquals(response.getRegistrationAccessToken(), rep.getRegistrationAccessToken());
         assertTrue(CollectionUtil.collectionEquals(Arrays.asList("code", "none"), response.getResponseTypes()));
         assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN), response.getGrantTypes()));
+        assertNotNull(response.getClientSecret());
+        assertEquals(0, response.getClientSecretExpiresAt().intValue());
     }
 
     @Test
                diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
index 900767f..ec800ed 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
@@ -21,12 +21,15 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.representations.oidc.TokenMetadataRepresentation;
+import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.KeycloakModelUtils;
@@ -112,7 +115,9 @@ public class TokenIntrospectionTest extends TestRealmKeycloakTest {
         AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
         String tokenResponse = oauth.introspectAccessTokenWithClientCredential("confidential-cli", "bad_credential", accessTokenResponse.getAccessToken());
 
-        assertEquals("{\"error_description\":\"Authentication failed.\",\"error\":\"invalid_request\"}", tokenResponse);
+        OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(tokenResponse, OAuth2ErrorRepresentation.class);
+        Assert.assertEquals("Authentication failed.", errorRep.getErrorDescription());
+        Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
     }
 
     @Test
@@ -157,7 +162,9 @@ public class TokenIntrospectionTest extends TestRealmKeycloakTest {
         AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
         String tokenResponse = oauth.introspectAccessTokenWithClientCredential("public-cli", "it_doesnt_matter", accessTokenResponse.getAccessToken());
 
-        assertEquals("{\"error_description\":\"Client not allowed.\",\"error\":\"invalid_request\"}", tokenResponse);
+        OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(tokenResponse, OAuth2ErrorRepresentation.class);
+        Assert.assertEquals("Client not allowed.", errorRep.getErrorDescription());
+        Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
     }
 
     @Test