Repository: gravitee-io/graviteeio-access-management
Pull request #589 (2019-05-31 01:08:37)

redirect_uris management + additional behaviour
In order to run NRT, you must merge this [PR](https://github.com/gravitee-io/graviteeio-access-management/pull/592) before.

This fix issue [#2297](https://github.com/gravitee-io/issues/issues/2297)

Set redirect_uri as mandatory in the UI when grant_type require it
Set redirect_uris as not mandatory in DCR when grant_type does not require it
Remove default openid scope in DCR
Forbid selection of refresh_token grant when not necessary (DCR & UI)
Discovery grant & response types values are now delivered through Utils services
Add device_code grant (but not into the supported grant)
Some UI documentation improvements


Patch:
diff --git a/Makefile b/Makefile
index 3d91ed3c21..ee4ccd32a2 100644
--- a/Makefile
+++ b/Makefile
@@ -156,6 +156,7 @@ postman: ## Run postman non regression test (require newman npm module)
 	@newman run postman/collections/graviteeio-am-openid-core-collection.json -e postman/environment/dev.json --ignore-redirects --insecure --bail
 	@newman run postman/collections/graviteeio-am-openid-dcr-collection.json -e postman/environment/dev.json --ignore-redirects --insecure --bail
 	@newman run postman/collections/graviteeio-am-scim-collection.json -e postman/environment/dev.json --ignore-redirects --insecure --bail
+	@newman run postman/collections/graviteeio-am-client-management-collection.json -e postman/environment/dev.json --ignore-redirects --insecure --bail
 	@newman run postman/collections/graviteeio-am-user-management-collection.json -e postman/environment/dev.json --ignore-redirects --insecure --bail
 
 oidctest-run: oidctest-install oidctest-start ## Run openid-certification tools, using same docker network
diff --git a/gravitee-am-common/src/main/java/io/gravitee/am/common/oauth2/GrantType.java b/gravitee-am-common/src/main/java/io/gravitee/am/common/oauth2/GrantType.java
index ff69e9752f..42e3deb7bc 100644
--- a/gravitee-am-common/src/main/java/io/gravitee/am/common/oauth2/GrantType.java
+++ b/gravitee-am-common/src/main/java/io/gravitee/am/common/oauth2/GrantType.java
@@ -55,14 +55,20 @@ public interface GrantType {
      *
      * See <a href="https://tools.ietf.org/html/rfc7523#section-2.1">2.1. Using JWTs as Authorization Grant</a>
      */
-    String JWT_BEARER ="urn:ietf:params:oauth:grant-type:jwt-bearer";
+    String JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer";
+
+    /**
+     * Device code flow
+     * See <a href="https://tools.ietf.org/html/draft-ietf-oauth-device-flow-15#section-3.4">3.4 Device Access Token Request</a>
+     */
+    String DEVIDE_CODE = "urn:ietf:params:oauth:grant-type:device_code";
 
     /**
      * SAML 2.0 Bearer
      *
      * See <a href="https://tools.ietf.org/html/rfc7522#section-2.1">2.1. Using SAML Assertions as Authorization Grants</a>
      */
-    String SAML2_BEARER ="urn:ietf:params:oauth:grant-type:saml2-bearer";
+    String SAML2_BEARER = "urn:ietf:params:oauth:grant-type:saml2-bearer";
 
     /**
      * Hybrid
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/impl/DynamicClientRegistrationServiceImpl.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/impl/DynamicClientRegistrationServiceImpl.java
index 8acd6ccd86..4e3b49a6ec 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/impl/DynamicClientRegistrationServiceImpl.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/impl/DynamicClientRegistrationServiceImpl.java
@@ -50,8 +50,6 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.*;
 
-import static io.gravitee.am.common.oidc.Scope.SCOPE_DELIMITER;
-
 /**
  * @author Alexandre FARIA (contact at alexandrefaria.net)
  * @author GraviteeSource Team
@@ -156,35 +154,23 @@ public class DynamicClientRegistrationServiceImpl implements DynamicClientRegist
     @Override
     public Single<DynamicClientRegistrationRequest> validateClientRegistrationRequest(final DynamicClientRegistrationRequest request) {
         LOGGER.debug("Validating dynamic client registration payload");
-
-        if(request==null) {
-            return Single.error(new InvalidClientMetadataException());
-        }
-
-        return this.validateRedirectUri(request)
-                .flatMap(this::validateResponseType)
-                .flatMap(this::validateGrantType)
-                .flatMap(this::validateSubjectType)
-                .flatMap(this::validateRequestUri)
-                .flatMap(this::validateSectorIdentifierUri)
-                .flatMap(this::validateJKWs)
-                .flatMap(this::validateUserinfoSigningAlgorithm)
-                .flatMap(this::validateUserinfoEncryptionAlgorithm)
-                .flatMap(this::validateIdTokenSigningAlgorithm)
-                .flatMap(this::validateIdTokenEncryptionAlgorithm)
-                .flatMap(this::validateScopes);
+        return this.validateClientRegistrationRequest(request,false);
     }
 
     @Override
     public Single<DynamicClientRegistrationRequest> validateClientPatchRequest(DynamicClientRegistrationRequest request) {
         LOGGER.debug("Validating dynamic client registration payload : patch");
+        return this.validateClientRegistrationRequest(request,true);
+    }
 
+    private Single<DynamicClientRegistrationRequest> validateClientRegistrationRequest(final DynamicClientRegistrationRequest request, boolean isPatch) {
         if(request==null) {
             return Single.error(new InvalidClientMetadataException());
         }
 
-        return this.validateResponseType(request)
+        return this.validateRedirectUri(request, isPatch)
                 .flatMap(this::validateGrantType)
+                .flatMap(this::validateResponseType)
                 .flatMap(this::validateSubjectType)
                 .flatMap(this::validateRequestUri)
                 .flatMap(this::validateSectorIdentifierUri)
@@ -195,18 +181,30 @@ public class DynamicClientRegistrationServiceImpl implements DynamicClientRegist
                 .flatMap(this::validateIdTokenEncryptionAlgorithm);
     }
 
-    private Single<DynamicClientRegistrationRequest> validateRedirectUri(DynamicClientRegistrationRequest request) {
-        //Redirect_uri is required, must be informed and filled without null values.
-        if(request.getRedirectUris()==null || !request.getRedirectUris().isPresent() || request.getRedirectUris().get().isEmpty()) {
+    /**
+     * According to openid specification, redirect_uris are REQUIRED in the request for creation.
+     * But according to the grant type, it may be null or empty.
+     * @param request DynamicClientRegistrationRequest
+     * @param isPatch true if only updating some fields (else means all fields will overwritten)
+     * @return DynamicClientRegistrationRequest
+     */
+    private Single<DynamicClientRegistrationRequest> validateRedirectUri(DynamicClientRegistrationRequest request, boolean isPatch) {
+
+        //Except for patching a client, redirect_uris metadata is required but may be null or empty.
+        if(!isPatch && request.getRedirectUris() == null) {
             return Single.error(new InvalidRedirectUriException());
         }
+
         return Single.just(request);
     }
 
     private Single<DynamicClientRegistrationRequest> validateResponseType(DynamicClientRegistrationRequest request) {
         //if response_type provided, they must be valid.
         if(request.getResponseTypes()!=null) {
-            if(!ResponseTypeUtils.isValidResponseType(request.getResponseTypes().get())) {
+            if(!request.getResponseTypes().isPresent()) {
+                request.setResponseTypes(Optional.of(Arrays.asList()));
+            }
+            if(!ResponseTypeUtils.isSupportedResponseType(request.getResponseTypes().get())) {
                 return Single.error(new InvalidClientMetadataException("Invalid response type."));
             }
         }
@@ -216,7 +214,7 @@ public class DynamicClientRegistrationServiceImpl implements DynamicClientRegist
     private Single<DynamicClientRegistrationRequest> validateGrantType(DynamicClientRegistrationRequest request) {
         //if grant_type provided, they must be valid.
         if(request.getGrantTypes()!=null) {
-            if(!GrantTypeUtils.isValidGrantType(request.getGrantTypes().get())) {
+            if (!GrantTypeUtils.isSupportedGrantType(request.getGrantTypes().get())) {
                 return Single.error(new InvalidClientMetadataException("Missing or invalid grant type."));
             }
         }
@@ -376,27 +374,6 @@ public class DynamicClientRegistrationServiceImpl implements DynamicClientRegist
         return Single.just(request);
     }
 
-    /**
-     * Here the target is not to validate all scopes but ensure that openid is well included.
-     * The scopes validations are done later (validateMetadata) on the process.
-     * @param request DynamicClientRegistrationRequest
-     * @return DynamicClientRegistrationRequest
-     */
-    private Single<DynamicClientRegistrationRequest> validateScopes(DynamicClientRegistrationRequest request) {
-
-        if(request.getScope()!=null && request.getScope().isPresent()) {
-            if(request.getScope().get().stream().filter(Scope.OPENID.getKey()::equals).count()==0) {
-                List scopes = new LinkedList(request.getScope().get());
-                scopes.add(Scope.OPENID.getKey());
-                request.setScope(Optional.of(String.join(SCOPE_DELIMITER,scopes)));
-            }
-        } else {
-            request.setScope(Optional.of(Scope.OPENID.getKey()));
-        }
-
-        return Single.just(request);
-    }
-
     /**
      * Check Uri is well formatted
      * @param uri String
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/discovery/impl/OpenIDDiscoveryServiceImpl.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/discovery/impl/OpenIDDiscoveryServiceImpl.java
index c08c3ff957..59fc6b8034 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/discovery/impl/OpenIDDiscoveryServiceImpl.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/main/java/io/gravitee/am/gateway/handler/oidc/service/discovery/impl/OpenIDDiscoveryServiceImpl.java
@@ -26,6 +26,8 @@ import io.gravitee.am.gateway.handler.oidc.service.discovery.OpenIDDiscoveryServ
 import io.gravitee.am.gateway.handler.oidc.service.discovery.OpenIDProviderMetadata;
 import io.gravitee.am.gateway.handler.oidc.service.utils.SubjectTypeUtils;
 import io.gravitee.am.model.Domain;
+import io.gravitee.am.service.utils.GrantTypeUtils;
+import io.gravitee.am.service.utils.ResponseTypeUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.util.Arrays;
@@ -72,8 +74,8 @@ public class OpenIDDiscoveryServiceImpl implements OpenIDDiscoveryService {
 
         // supported parameters
         openIDProviderMetadata.setScopesSupported(Stream.of(Scope.values()).map(Scope::getKey).collect(Collectors.toList()));
-        openIDProviderMetadata.setResponseTypesSupported(Arrays.asList(ResponseType.CODE, ResponseType.TOKEN, io.gravitee.am.common.oidc.ResponseType.ID_TOKEN, io.gravitee.am.common.oidc.ResponseType.ID_TOKEN_TOKEN, io.gravitee.am.common.oidc.ResponseType.CODE_ID_TOKEN, io.gravitee.am.common.oidc.ResponseType.CODE_TOKEN, io.gravitee.am.common.oidc.ResponseType.CODE_ID_TOKEN_TOKEN));
-        openIDProviderMetadata.setGrantTypesSupported(Arrays.asList(GrantType.CLIENT_CREDENTIALS, GrantType.PASSWORD, GrantType.IMPLICIT, GrantType.AUTHORIZATION_CODE, GrantType.REFRESH_TOKEN, GrantType.JWT_BEARER));
+        openIDProviderMetadata.setResponseTypesSupported(ResponseTypeUtils.getSupportedResponseTypes());
+        openIDProviderMetadata.setGrantTypesSupported(GrantTypeUtils.getSupportedGrantTypes());
         openIDProviderMetadata.setIdTokenSigningAlgValuesSupported(JWAlgorithmUtils.getSupportedIdTokenSigningAlg());
         openIDProviderMetadata.setIdTokenEncryptionAlgValuesSupported(JWAlgorithmUtils.getSupportedIdTokenResponseAlg());
         openIDProviderMetadata.setIdTokenEncryptionEncValuesSupported(JWAlgorithmUtils.getSupportedIdTokenResponseEnc());
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/ClientServiceImpl.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/ClientServiceImpl.java
index 750f9a60a8..3a0e963ade 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/ClientServiceImpl.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/impl/ClientServiceImpl.java
@@ -28,8 +28,20 @@ import io.gravitee.am.model.common.event.Payload;
 import io.gravitee.am.model.common.event.Type;
 import io.gravitee.am.repository.management.api.ClientRepository;
 import io.gravitee.am.repository.oauth2.api.AccessTokenRepository;
-import io.gravitee.am.service.*;
-import io.gravitee.am.service.exception.*;
+import io.gravitee.am.service.AuditService;
+import io.gravitee.am.service.ClientService;
+import io.gravitee.am.service.DomainService;
+import io.gravitee.am.service.EmailTemplateService;
+import io.gravitee.am.service.FormService;
+import io.gravitee.am.service.IdentityProviderService;
+import io.gravitee.am.service.ScopeService;
+import io.gravitee.am.service.exception.AbstractManagementException;
+import io.gravitee.am.service.exception.ClientAlreadyExistsException;
+import io.gravitee.am.service.exception.ClientNotFoundException;
+import io.gravitee.am.service.exception.DomainNotFoundException;
+import io.gravitee.am.service.exception.InvalidClientMetadataException;
+import io.gravitee.am.service.exception.InvalidRedirectUriException;
+import io.gravitee.am.service.exception.TechnicalManagementException;
 import io.gravitee.am.service.model.NewClient;
 import io.gravitee.am.service.model.PatchClient;
 import io.gravitee.am.service.model.TopClient;
@@ -46,9 +58,17 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
 
 import java.net.URI;
-import java.util.*;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -284,6 +304,9 @@ public class ClientServiceImpl implements ClientService {
                     client.setClientSecret(newClient.getClientSecret());
                     client.setClientName(newClient.getClientName());
                     client.setDomain(domain);
+                    //AM UI first step client creation does not provide field to specify redirect_uris, so better no use code grant by default.
+                    client.setAuthorizedGrantTypes(Arrays.asList());
+                    client.setResponseTypes(Arrays.asList());
                     return Single.just(client);
                 })
                 .flatMap(client -> this.create(client))
@@ -322,7 +345,7 @@ public class ClientServiceImpl implements ClientService {
         client.setCreatedAt(new Date());
         client.setUpdatedAt(client.getCreatedAt());
 
-        return this.validateClientMetadata(client.getDomain(), client)
+        return this.validateClientMetadata(client)
                 .flatMap(clientRepository::create)
                 .flatMap(justCreatedClient -> {
                     // Reload domain to take care about client creation
@@ -343,8 +366,8 @@ public class ClientServiceImpl implements ClientService {
         return clientRepository.findById(client.getId())
                 .switchIfEmpty(Maybe.error(new ClientNotFoundException(client.getId())))
                 .flatMapSingle(found -> Single.just(client))
-                .flatMap(toUpdate -> this.validateClientMetadata(toUpdate.getDomain(), toUpdate))
-                .flatMap(toUpdate -> this.updateClientAndReloadDomain(toUpdate.getDomain(), toUpdate))
+                .flatMap(this::validateClientMetadata)
+                .flatMap(this::updateClientAndReloadDomain)
                 .onErrorResumeNext(this::handleError);
     }
 
@@ -366,8 +389,8 @@ public class ClientServiceImpl implements ClientService {
                     }
                 })
                 .flatMap(toPatch -> Single.just(patchClient.patch(toPatch, forceNull))
-                        .flatMap(client -> this.validateClientMetadata(domain, client))
-                        .flatMap(client -> this.updateClientAndReloadDomain(domain, client))
+                        .flatMap(this::validateClientMetadata)
+                        .flatMap(this::updateClientAndReloadDomain)
                         .doOnSuccess(client -> auditService.report(AuditBuilder.builder(ClientAuditBuilder.class).principal(principal).type(EventType.CLIENT_UPDATED).oldValue(toPatch).client(client)))
                         .doOnError(throwable -> auditService.report(AuditBuilder.builder(ClientAuditBuilder.class).principal(principal).type(EventType.CLIENT_UPDATED).throwable(throwable))))
                 .onErrorResumeNext(this::handleError);
@@ -421,7 +444,7 @@ public class ClientServiceImpl implements ClientService {
                     client.setClientSecret(SecureRandomString.generate());
 
                     // update client and reload domain
-                    return updateClientAndReloadDomain(domain, client);
+                    return updateClientAndReloadDomain(client);
                 })
                 .onErrorResumeNext(this::handleError)
                 .doOnSuccess(client -> auditService.report(AuditBuilder.builder(ClientAuditBuilder.class).principal(principal).type(EventType.CLIENT_SECRET_RENEWED).client(client)))
@@ -434,71 +457,91 @@ public class ClientServiceImpl implements ClientService {
      * We try to enable Dynamic Client Registration on client side while it is not enabled on domain.
      * The redirect_uris do not respect domain conditions (localhost, scheme and wildcard)
      * </pre>
-     * @param domainId domain
      * @param client client to check
      * @return a client only if every conditions are respected.
      */
-    private Single<Client> validateClientMetadata(String domainId, Client client) {
+    private Single<Client> validateClientMetadata(Client client) {
+        return GrantTypeUtils.validateGrantTypes(client)
+                .flatMap(this::validateRedirectUris)
+                .flatMap(this::validateScopes);
+    }
 
-        return domainService.findById(domainId)
-                .switchIfEmpty(Maybe.error(new DomainNotFoundException(domainId)))
+    private Single<Client> validateRedirectUris(Client client) {
+        return domainService.findById(client.getDomain())
+                .switchIfEmpty(Maybe.error(new DomainNotFoundException(client.getDomain())))
                 .flatMapSingle(domain -> {
+
                     //check redirect_uri
+                    if(GrantTypeUtils.isRedirectUriRequired(client.getAuthorizedGrantTypes()) && CollectionUtils.isEmpty(client.getRedirectUris())) {
+                        return Single.error(new InvalidRedirectUriException());
+                    }
+
+                    //check redirect_uri content
                     if (client.getRedirectUris() != null) {
                         for (String redirectUri : client.getRedirectUris()) {
 
-                            URI uri = UriBuilder.fromURIString(redirectUri).build();
+                            try {
+                                URI uri = UriBuilder.fromURIString(redirectUri).build();
 
-                            if (!domain.isRedirectUriLocalhostAllowed() && UriBuilder.isLocalhost(uri.getHost())) {
-                                return Single.error(new InvalidRedirectUriException("localhost is forbidden"));
-                            }
-                            //check http scheme
-                            if (!domain.isRedirectUriUnsecuredHttpSchemeAllowed() && uri.getScheme().equalsIgnoreCase("http")) {
-                                return Single.error(new InvalidRedirectUriException("Unsecured http scheme is forbidden"));
+                                if(uri.getScheme()==null) {
+                                    return Single.error(new InvalidRedirectUriException("redirect_uri : " + redirectUri + " is malformed"));
+                                }
+
+                                if (!domain.isRedirectUriLocalhostAllowed() && UriBuilder.isHttp(uri.getScheme()) && UriBuilder.isLocalhost(uri.getHost())) {
+                                    return Single.error(new InvalidRedirectUriException("localhost is forbidden"));
+                                }
+                                //check http scheme
+                                if (!domain.isRedirectUriUnsecuredHttpSchemeAllowed() && uri.getScheme().equalsIgnoreCase("http")) {
+                                    return Single.error(new InvalidRedirectUriException("Unsecured http scheme is forbidden"));
+                                }
+                                //check wildcard
+                                if (!domain.isRedirectUriWildcardAllowed() && uri.getPath().contains("*")) {
+                                    return Single.error(new InvalidRedirectUriException("Wildcard are forbidden"));
+                                }
                             }
-                            //check wildcard
-                            if (!domain.isRedirectUriWildcardAllowed() && uri.getPath().contains("*")) {
-                                return Single.error(new InvalidRedirectUriException("Wildcard are forbidden"));
+                            catch (IllegalArgumentException | URISyntaxException ex) {
+                                return Single.error(new InvalidRedirectUriException("redirect_uri : " + redirectUri + " is malformed"));
                             }
                         }
                     }
+                    return Single.just(client);
+                });
+    }
 
-                    // check scopes and scope approvals
-                    return scopeService.validateScope(domainId, client.getScopes())
-                            .map(isValid -> {
-                                // scopes are valid, let's check scope approvals
-                                if (isValid && client.getScopeApprovals() != null) {
-                                    Map<String, Integer> scopeApprovals = client.getScopeApprovals()
-                                            .entrySet()
-                                            .stream()
-                                            .filter(entry -> client.getScopes() != null && client.getScopes().contains(entry.getKey()))
-                                            .collect(Collectors.toMap(
-                                                    entry -> entry.getKey(),
-                                                    entry -> entry.getValue()));
-                                    client.setScopeApprovals(scopeApprovals);
-                                }
-                                return isValid;
-                            });
+    private Single<Client> validateScopes(Client client) {
+        // check scopes and scope approvals
+        return scopeService.validateScope(client.getDomain(), client.getScopes())
+                .map(isValid -> {
+                    // scopes are valid, let's check scope approvals
+                    if (isValid && client.getScopeApprovals() != null) {
+                        Map<String, Integer> scopeApprovals = client.getScopeApprovals()
+                                .entrySet()
+                                .stream()
+                                .filter(entry -> client.getScopes() != null && client.getScopes().contains(entry.getKey()))
+                                .collect(Collectors.toMap(
+                                        entry -> entry.getKey(),
+                                        entry -> entry.getValue()));
+                        client.setScopeApprovals(scopeApprovals);
+                    }
+                    return isValid;
                 })
                 .flatMap(isValid -> {
                     if (!isValid) {
                         //last boolean come from scopes validation...
                         return Single.error(new InvalidClientMetadataException("non valid scopes"));
                     }
-                    //ensure correspondance between response & grant types.
-                    GrantTypeUtils.completeGrantTypeCorrespondance(client);
 
                     return Single.just(client);
                 });
     }
 
-    private Single<Client> updateClientAndReloadDomain(String domain, Client client) {
+    private Single<Client> updateClientAndReloadDomain(Client client) {
         client.setUpdatedAt(new Date());
         return clientRepository.update(client)
                 .flatMap(updatedClient -> {
                     // Reload domain to take care about client update
                     Event event = new Event(Type.CLIENT, new Payload(updatedClient.getId(), client.getDomain(), Action.UPDATE));
-                    return domainService.reload(domain, event).flatMap(domain1 -> Single.just(updatedClient));
+                    return domainService.reload(client.getDomain(), event).flatMap(domain1 -> Single.just(updatedClient));
                 });
     }
 
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/GrantTypeUtils.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/GrantTypeUtils.java
index b90163a01c..e39ca58b90 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/GrantTypeUtils.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/GrantTypeUtils.java
@@ -16,6 +16,8 @@
 package io.gravitee.am.service.utils;
 
 import io.gravitee.am.model.Client;
+import io.gravitee.am.service.exception.InvalidClientMetadataException;
+import io.reactivex.Single;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -31,21 +33,82 @@ import static io.gravitee.am.common.oidc.ResponseType.*;
  */
 public class GrantTypeUtils {
 
-    private static final Set<String> VALID_GRANT_TYPES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
-            AUTHORIZATION_CODE, IMPLICIT, REFRESH_TOKEN, CLIENT_CREDENTIALS, PASSWORD, JWT_BEARER, SAML2_BEARER
+    private static final Set<String> SUPPORTED_GRANT_TYPES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+            AUTHORIZATION_CODE, IMPLICIT, REFRESH_TOKEN, CLIENT_CREDENTIALS, PASSWORD, JWT_BEARER//, DEVIDE_CODE, SAML2_BEARER
     )));
 
     /**
-     * Throw InvalidClientMetadataException if null or empty, or contains unknown grant types.
+     * <pre>
+     * Check:
+     *  - grant types are null or empty, or contains unknown grant types.
+     *  - refresh_token does not come with authorization_code, password or client_credentials grant.
+     *  - client_credentials grant come with another grant that require user authentication.
+     * </pre>
+     * @param client Client with grant_type to validate.
+     * @return Single client or error
+     */
+    public static Single<Client> validateGrantTypes(Client client) {
+
+        if(client==null) {
+            return Single.error(new InvalidClientMetadataException("No client to validate grant"));
+        }
+
+        if(client.getAuthorizedGrantTypes()==null || client.getAuthorizedGrantTypes().isEmpty()) {
+            return Single.just(client);
+        }
+
+        if(!isSupportedGrantType(client.getAuthorizedGrantTypes())) {
+            return Single.error(new InvalidClientMetadataException("Missing or invalid grant type."));
+        }
+
+        //Ensure correspondance between response & grant types.
+        completeGrantTypeCorrespondance(client);
+
+        //refresh_token are not allowed for all grant types...
+        Set<String> grantTypeSet = Collections.unmodifiableSet(new HashSet<>(client.getAuthorizedGrantTypes()));
+        if(grantTypeSet.contains(REFRESH_TOKEN)) {
+            //Hybrid is not managed yet and AM does not support refresh token for client_credentials for now...
+            List<String> allowedRefreshTokenGrant = Arrays.asList(AUTHORIZATION_CODE, PASSWORD, JWT_BEARER);//, CLIENT_CREDENTIALS, HYBRID);
+            //return true if there is no element in common
+            if(Collections.disjoint(client.getAuthorizedGrantTypes(), allowedRefreshTokenGrant)) {
+                return Single.error(new InvalidClientMetadataException(
+                        REFRESH_TOKEN+" grant type must be associated with one of "+String.join(", ",allowedRefreshTokenGrant)
+                ));
+            }
+        }
+
+        /*
+         * Uncomment when ready to setup a "non expert mode" on the AM user interface"
+         * It is not recommended to mix client and user authentication within the same application.
+         * (Aka client_credentials and authorization_code, implicit or password...)
+        if(grantTypeSet.contains(CLIENT_CREDENTIALS)) {
+            //If client_credentials come with at least one of belows grant
+            if(!Collections.disjoint(client.getAuthorizedGrantTypes(),Arrays.asList(AUTHORIZATION_CODE, IMPLICIT, PASSWORD, HYBRID, DEVIDE_CODE))) {
+                return Single.error(new InvalidClientMetadataException(
+                        CLIENT_CREDENTIALS+" must not be associated with another grant that imply user authentication"
+                ));
+            }
+        }
+        */
+
+        return Single.just(client);
+    }
+
+    public static List<String> getSupportedGrantTypes() {
+        return Collections.unmodifiableList(SUPPORTED_GRANT_TYPES.stream().sorted().collect(Collectors.toList()));
+    }
+
+    /**
      * @param grantTypes Array of grant_type to validate.
      */
-    public static boolean isValidGrantType(List<String> grantTypes) {
+    public static boolean isSupportedGrantType(List<String> grantTypes) {
         if(grantTypes==null || grantTypes.isEmpty()) {
             return false;
         }
 
+        //Check grant types are all known
         for(String grantType:grantTypes) {
-            if(!isValidGrantType(grantType)) {
+            if(!isSupportedGrantType(grantType)) {
                 return false;
             }
         }
@@ -57,8 +120,29 @@ public class GrantTypeUtils {
      * Check if grant type is known/supported.
      * @param grantType String grant_type to validate.
      */
-    public static boolean isValidGrantType(String grantType) {
-        return VALID_GRANT_TYPES.contains(grantType);
+    public static boolean isSupportedGrantType(String grantType) {
+        return SUPPORTED_GRANT_TYPES.contains(grantType);
+    }
+
+    /**
+     * <pre>
+     * According to the specification: https://tools.ietf.org/html/rfc6749#section-10.6
+     * Authorization Server MUST require public clients and SHOULD require confidential clients to register their redirection URIs.
+     * confidential clients are clients that can keep their credentials secrets, ex:
+     *  - web application (using a web server to save their credentials) : authorization_code
+     *  - server application (considering credentials saved on a server as safe) : client_credentials
+     * by opposition to confidential, public clients are clients than can not keep their credentials as secret, ex:
+     *  - Single Page Application : implicit
+     *  - Native mobile application : authorization_code
+     * Because mobile and web application use the same grant, we force redirect_uri only for implicit grant.
+     * </pre>
+     * @param grantTypes Array of grant_type
+     * @return true if at least one of the grant type included in the array require a redirect_uri.
+     */
+    public static boolean isRedirectUriRequired(List<String> grantTypes) {
+        List<String> requireRedirectUri = Arrays.asList(IMPLICIT);//, HYBRID); Add Hybrid once supported...
+        //return true if there's no grant type matching
+        return grantTypes!=null && !Collections.disjoint(grantTypes, requireRedirectUri);
     }
 
     /**
@@ -69,7 +153,7 @@ public class GrantTypeUtils {
      * token id_token      : implicit
      * code id_token       : authorization_code, implicit
      * code token          : authorization_code, implicit
-     * code token id_token : authorization_code, implicit
+     * code id_token token : authorization_code, implicit
      *
      * @param client Client to analyse.
      */
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/ResponseTypeUtils.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/ResponseTypeUtils.java
index ab8d62fc73..5d6de6769e 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/ResponseTypeUtils.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/ResponseTypeUtils.java
@@ -32,21 +32,25 @@ import static io.gravitee.am.common.oidc.ResponseType.*;
  */
 public class ResponseTypeUtils {
 
-    private static final Set<String> VALID_RESPONSE_TYPES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+    private static final Set<String> SUPPORTED_RESPONSE_TYPES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
             CODE, TOKEN, ID_TOKEN, ID_TOKEN_TOKEN, CODE_TOKEN, CODE_ID_TOKEN, CODE_ID_TOKEN_TOKEN
     )));
 
+    public static List<String> getSupportedResponseTypes() {
+        return Collections.unmodifiableList(SUPPORTED_RESPONSE_TYPES.stream().sorted().collect(Collectors.toList()));
+    }
+
     /**
-     * Throw InvalidClientMetadataException if null or empty, or contains unknown response types.
+     * Throw InvalidClientMetadataException if null, or contains unknown response types.
      * @param responseTypes Array of response_type to validate.
      */
-    public static boolean isValidResponseType(List<String> responseTypes) {
-        if (responseTypes == null || responseTypes.isEmpty()) {
+    public static boolean isSupportedResponseType(List<String> responseTypes) {
+        if (responseTypes == null) {
             return false;
         }
 
         for (String responseType : responseTypes) {
-            if (!isValidResponseType(responseType)) {
+            if (!isSupportedResponseType(responseType)) {
                 return false;
             }
         }
@@ -58,8 +62,8 @@ public class ResponseTypeUtils {
      * Throw InvalidClientMetadataException if null or contains unknown response types.
      * @param responseType String to response_type validate.
      */
-    public static boolean isValidResponseType(String responseType) {
-        return VALID_RESPONSE_TYPES.contains(responseType);
+    public static boolean isSupportedResponseType(String responseType) {
+        return SUPPORTED_RESPONSE_TYPES.contains(responseType);
     }
 
     /**
diff --git a/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/UriBuilder.java b/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/UriBuilder.java
index 483db6716d..085e2be053 100644
--- a/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/UriBuilder.java
+++ b/gravitee-am-service/src/main/java/io/gravitee/am/service/utils/UriBuilder.java
@@ -30,43 +30,45 @@ import java.util.regex.Pattern;
  */
 public class UriBuilder {
 
-    private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("([^&=]+)(=?)([^&]+)?");
+    //private static final Pattern QUERY_PARAM_PATTERN = Pattern.compile("([^&=]+)(=?)([^&]+)?");
 
-    private static final String SCHEME_PATTERN = "([^:/?#]+):";
+    private static final String SCHEME_REGEX = "([^:/?#]+):";
 
-    private static final String HTTP_PATTERN = "(?i)(http|https):";
+    private static final String HTTP_REGEX = "(?i)(http|https):";
 
-    private static final String USERINFO_PATTERN = "([^@\\[/?#]*)";
+    private static final String USERINFO_REGEX = "([^@\\[/?#]*)";
 
-    private static final String HOST_IPV4_PATTERN = "[^\\[/?#:]*";
+    private static final String HOST_IPV4_REGEX = "[^\\[/?#:]*";
 
-    private static final String HOST_IPV6_PATTERN = "\\[[\\p{XDigit}\\:\\.]*[%\\p{Alnum}]*\\]";
+    private static final String HOST_IPV6_REGEX = "\\[[\\p{XDigit}\\:\\.]*[%\\p{Alnum}]*\\]";
 
-    private static final String HOST_PATTERN = "(" + HOST_IPV6_PATTERN + "|" + HOST_IPV4_PATTERN + ")";
+    private static final String HOST_REGEX = "(" + HOST_IPV6_REGEX + "|" + HOST_IPV4_REGEX + ")";
 
-    private static final String PORT_PATTERN = "(\\d*(?:\\{[^/]+?\\})?)";
+    private static final String PORT_REGEX = "(\\d*(?:\\{[^/]+?\\})?)";
 
-    private static final String PATH_PATTERN = "([^?#]*)";
+    private static final String PATH_REGEX = "([^?#]*)";
 
-    private static final String QUERY_PATTERN = "([^#]*)";
+    private static final String QUERY_REGEX = "([^#]*)";
 
-    private static final String LAST_PATTERN = "(.*)";
+    private static final String LAST_REGEX = "(.*)";
 
     // Regex patterns that matches URIs. See RFC 3986, appendix B
     private static final Pattern URI_PATTERN = Pattern.compile(
-            "^(" + SCHEME_PATTERN + ")?" + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN +
-                    ")?" + ")?" + PATH_PATTERN + "(\\?" + QUERY_PATTERN + ")?" + "(#" + LAST_PATTERN + ")?");
+            "^(" + SCHEME_REGEX + ")?" + "(//(" + USERINFO_REGEX + "@)?" + HOST_REGEX + "(:" + PORT_REGEX +
+                    ")?" + ")?" + PATH_REGEX + "(\\?" + QUERY_REGEX + ")?" + "(#" + LAST_REGEX + ")?");
 
     private static final Pattern HTTP_URL_PATTERN = Pattern.compile(
-            "^" + HTTP_PATTERN + "(//(" + USERINFO_PATTERN + "@)?" + HOST_PATTERN + "(:" + PORT_PATTERN +
-                    ")?" + ")?" + PATH_PATTERN + "(\\?" + QUERY_PATTERN + ")?" + "(#" + LAST_PATTERN + ")?");
+            "^" + HTTP_REGEX + "(//(" + USERINFO_REGEX + "@)?" + HOST_REGEX + "(:" + PORT_REGEX +
+                    ")?" + ")?" + PATH_REGEX + "(\\?" + QUERY_REGEX + ")?" + "(#" + LAST_REGEX + ")?");
 
-    private static final String LOCALHOST_HOST_PATTERN = "^localhost$";
-    private static final String LOCALHOST_IPV4_PATTERN = "^127(?:\\.[0-9]+){0,2}\\.[0-9]+$";
-    private static final String LOCALHOST_IPV6_PATTERN = "^(?:0*\\:)*?:?0*1$";
+    private static final Pattern HTTP_PATTERN = Pattern.compile(HTTP_REGEX.replace(":",""));
+
+    private static final String LOCALHOST_HOST_REGEX = "^localhost$";
+    private static final String LOCALHOST_IPV4_REGEX = "^127(?:\\.[0-9]+){0,2}\\.[0-9]+$";
+    private static final String LOCALHOST_IPV6_REGEX = "^(?:0*\\:)*?:?0*1$";
 
     private static final Pattern LOCALHOST_PATTERN = Pattern.compile(
-            LOCALHOST_HOST_PATTERN +"|"+LOCALHOST_IPV4_PATTERN+"|"+ LOCALHOST_IPV6_PATTERN);
+            LOCALHOST_HOST_REGEX +"|"+ LOCALHOST_IPV4_REGEX +"|"+ LOCALHOST_IPV6_REGEX);
 
     private String scheme;
     private String host;
@@ -214,6 +216,10 @@ public class UriBuilder {
         return new URI(scheme, userInfo, host, port, path, query, fragment);
     }
 
+    public static boolean isHttp(String scheme) {
+        return HTTP_PATTERN.matcher(scheme.toLowerCase()).matches();
+    }
+
     public static boolean isLocalhost(String host) {
         return LOCALHOST_PATTERN.matcher(host.toLowerCase()).matches();
     }
diff --git a/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.html b/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.html
index 8bef1ea70c..33ee160aee 100644
--- a/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.html
+++ b/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.html
@@ -219,7 +219,8 @@
         <b><i>authorization_code</i></b> for server side applications (web) or native applications (then combined with PKCE).<br>
         <b><i>implicit</i></b> must be used for Single Page Applications.<br>
         <b><i>password</i></b> should only be used for trusted applications <i>(means application and authorization server are managed within the same organization.)</i><br>
-        <b><i>client_credentials</i></b> should be used for server to server communications.<br>
+        <b><i>client_credentials</i></b> should be used for server to server communications.<br><br>
+        <b>It is not recommended to mix client and user authentication within the same application.</b> <i>(Aka client_credentials and authorization_code, implicit or password)</i><br>
     </small>
   </div>
   <h3>Response types</h3>
@@ -235,7 +236,7 @@
       <b><i>token id_token:</i></b> implicit<br>
       <b><i>code id_token:</i></b> authorization_code, implicit<br>
       <b><i>code token:</i></b> authorization_code, implicit<br>
-      <b><i>code token id_token:</i></b> authorization_code, implicit<br>
+      <b><i>code id_token token:</i></b> authorization_code, implicit<br>
     </small>
 
   </div>
diff --git a/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.ts b/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.ts
index b5cae1a202..a5157c1618 100644
--- a/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.ts
+++ b/gravitee-am-ui/src/app/domain/clients/client/settings/settings.component.ts
@@ -46,11 +46,11 @@ export class ClientSettingsComponent implements OnInit {
   identityProviders: any[] = [];
   certificates: any[] = [];
   scopes: any[] = [];
-  //responseTypes: any[] = ['code','token','id_token','id_token token','code token','code token id_token'];
+  //responseTypes: any[] = ['code','token','id_token','id_token token','code token','code id_token token'];
   responseTypes: any[] = [
     { value:'code', checked:false },
-    { value:'token', checked:false },
-    { value:'id_token', checked:false }
+    { value:'id_token', checked:false },
+    { value:'token', checked:false }
   ];
   grantTypes: any[] = [
     { name:'AUTHORIZATION CODE', value:'authorization_code', checked:false },
diff --git a/postman/collections/graviteeio-am-client-management-collection.json b/postman/collections/graviteeio-am-client-management-collection.json
new file mode 100644
index 0000000000..ec4b7cc701
--- /dev/null
+++ b/postman/collections/graviteeio-am-client-management-collection.json
@@ -0,0 +1,916 @@
+{
+	"info": {
+		"_postman_id": "73100933-53f5-45a2-9daa-1ca3bc04a523",
+		"name": "Gravitee.io - AM - Client Management",
+		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
+	},
+	"item": [
+		{
+			"name": "Prepare",
+			"item": [
+				{
+					"name": "Generate admin token",
+					"event": [
+						{
+							"listen": "test",
+							"script": {
+								"id": "571e9b59-b9e7-452c-9469-9786ded290a6",
+								"exec": [
+									"",
+									"pm.test(\"Status code is 200\", function () {",
+									"    pm.response.to.have.status(200);",
+									"});",
+									"",
+									"var token = JSON.parse(responseBody);",
+									"pm.environment.set('token', token.access_token);"
+								],
+								"type": "text/javascript"
+							}
+						}
+					],
+					"request": {
+						"method": "POST",
+						"header": [
+							{
+								"key": "Authorization",
+								"value": "Basic YWRtaW46YWRtaW5hZG1pbg=="
+							}
+						],
+						"body": {
+							"mode": "urlencoded",
+							"urlencoded": [
+								{
+									"key": "grant_type",
+									"value": "password",
+									"type": "text"
+								},
+								{
+									"key": "username",
+									"value": "admin",
+									"type": "text"
+								},
+								{
+									"key": "password",
+									"value": "adminadmin",
+									"type": "text"
+								}
+							]
+						},
+						"url": {
+							"raw": "{{management_url}}/admin/token",
+							"host": [
+								"{{management_url}}"
+							],
+							"path": [
+								"admin",
+								"token"
+							]
+						}
+					},
+					"response": []
+				},
+				{
+					"name": "Create client management domain",
+					"event": [
+						{
+							"listen": "test",
+							"script": {
+								"id": "b286f0fa-cfcc-45b9-863a-1dbc87fdf835",
+								"exec": [
+									"pm.test(\"Status code is 201\", function () {",
+									"    pm.response.to.have.status(201);",
+									"});",
+									"",
+									"var jsonData = pm.response.json();",
+									"pm.environment.set('domain', jsonData.id);"
+								],
+								"type": "text/javascript"
+							}
+						}
+					],
+					"request": {
+						"method": "POST",
+						"header": [
+							{
+								"key": "Content-Type",
+								"value": "application/json"
+							},
+							{
+								"key": "Authorization",
+								"value": "Bearer {{token}}"
+							}
+						],
+						"body": {
+							"mode": "raw",
+							"raw": "{\n\t\"name\": \"client-domain\", \n\t\"description\": \"test client management through Access Management API\"\n}"
+						},
+						"url": {
+							"raw": "{{management_url}}/management/domains/",
+							"host": [
+								"{{management_url}}"
+							],
+							"path": [
+								"management",
+								"domains",
+								""
+							]
+						}
+					},
+					"response": []
+				},
+				{
+					"name": "Start domain",
+					"event": [
+						{
+							"listen": "test",
+							"script": {
+								"id": "bfe78ac1-144a-4bbd-abf9-55e160e723bf",
+								"exec": [
+									"// wait for sync process",
+									"setTimeout(function(){}, 5000);"
+								],
+								"type": "text/javascript"
+							}
+						}
+					],
+					"request": {
+						"method": "PATCH",
+						"header": [
+							{
+								"key": "Content-Type",
+								"value": "application/json"
+							},
+							{
+								"key": "Authorization",
+								"value": "Bearer {{token}}"
+							}
+						],
+						"body": {
+							"mode": "raw",
+							"raw": "{\n  \"enabled\": true\n}"
+						},
+						"url": {
+							"raw": "{{management_url}}/management/domains/{{domain}}",
+							"host": [
+								"{{management_url}}"
+							],
+							"path": [
+								"management",
+								"domains",
+								"{{domain}}"
+							]
+						}
+					},
+					"response": []
+				},
+				{
+					"name": "well-known/openid-configuration",
+					"event": [
+						{
+							"listen": "test",
+							"script": {
+								"id": "5332b6f5-7419-4792-a30f-cce968d3d67e",
+								"exec": [
+									"pm.test(\"Status code is 200\", function () {",
+									"    pm.response.to.have.status(200);",
+									"});",
+									"",
+									"pm.test(\"Check discovery endpoints\", function () {",
+									"    pm.response.to.be.header('Content-Type', 'application/json');",
+									"    var body = pm.response.json();",
+									"    ",
+									"    pm.expect(body).to.have.property(\"token_endpoint\");",
+									"    pm.environment.set('tokenEndpoint', body.token_endpoint);",
+									"});"
+								],
+								"type": "text/javascript"
+							}
+						}
+					],
+					"request": {
+						"method": "GET",
+						"header": [],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
+						"url": {
+							"raw": "{{gateway_url}}/{{domain}}/oidc/.well-known/openid-configuration",
+							"host": [
+								"{{gateway_url}}"
+							],
+							"path": [
+								"{{domain}}",
+								"oidc",
+								".well-known",
+								"openid-configuration"
+							]
+						}
+					},
+					"response": []
+				}
+			]
+		},
+		{
+			"name": "Client Management",
+			"item": [
+				{
+					"name": "Invalid Case",
+					"item": [
+						{
+							"name": "Create client",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "fbe2362d-ad75-4baa-8825-b74218b047c7",
+										"exec": [
+											"pm.test(\"Status code is 201\", function () {",
+											"    pm.response.to.have.status(201);",
+											"});",
+											"",
+											"pm.test(\"grant and response types are empty\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.environment.set('client', body.id);",
+											"",
+											"    pm.expect(body).to.have.property('authorizedGrantTypes');",
+											"    pm.expect(body).to.have.property('responseTypes');",
+											"    pm.expect(body.authorizedGrantTypes).to.eql([]);",
+											"    pm.expect(body.responseTypes).to.eql([]);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"clientId\": \"my-client\",\n  \"clientSecret\": \"my-client-secret\"\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "missing redirect_uris",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c37cba72-91c2-4850-80cd-6fd3908e406e",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"missing redirect_uri\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.expect(body).to.have.property('message');",
+											"    pm.expect(body.message).to.eql('Missing or invalid redirect_uris.');",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\"implicit\"],\n  \"responseTypes\": [\"token\"]\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "missing grant associated to refresh_token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c37cba72-91c2-4850-80cd-6fd3908e406e",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"missing redirect_uri\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.expect(body).to.have.property('message');",
+											"    pm.expect(body.message).to.contains('refresh_token grant type must be associated with one of');",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\"refresh_token\"],\n  \"responseTypes\": []\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "client_credentials does not manage refresh_token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c37cba72-91c2-4850-80cd-6fd3908e406e",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"missing redirect_uri\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.expect(body).to.have.property('message');",
+											"    pm.expect(body.message).to.contains('refresh_token grant type must be associated with one of');",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\"refresh_token\",\"client_credentials\"],\n  \"responseTypes\": []\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Delete client",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "fbe2362d-ad75-4baa-8825-b74218b047c7",
+										"exec": [
+											"pm.test(\"Status code is 204\", function () {",
+											"    pm.response.to.have.status(204);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "DELETE",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"clientId\": \"my-client\",\n  \"clientSecret\": \"my-client-secret\"\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						}
+					],
+					"_postman_isSubFolder": true
+				},
+				{
+					"name": "Nominal Case",
+					"item": [
+						{
+							"name": "Create client",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "fbe2362d-ad75-4baa-8825-b74218b047c7",
+										"exec": [
+											"pm.test(\"Status code is 201\", function () {",
+											"    pm.response.to.have.status(201);",
+											"});",
+											"",
+											"",
+											"pm.test(\"default values\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.environment.set('client', body.id);",
+											"",
+											"    pm.expect(body).to.have.property('authorizedGrantTypes');",
+											"    pm.expect(body).to.have.property('responseTypes');",
+											"    pm.expect(body).to.have.property('applicationType');",
+											"",
+											"    pm.expect(body.authorizedGrantTypes).to.eql([]);",
+											"    pm.expect(body.responseTypes).to.eql([]);",
+											"    pm.expect(body.applicationType).to.eql('web');",
+											"    ",
+											"    pm.expect(body.clientName).to.eql('Unknown Client');",
+											"    pm.expect(body.tokenEndpointAuthMethod).to.eql('client_secret_basic');",
+											"    pm.expect(body.requireAuthTime).to.eql(false);",
+											"    pm.expect(body.accessTokenValiditySeconds).to.eql(7200);",
+											"    pm.expect(body.refreshTokenValiditySeconds).to.eql(14400);",
+											"    pm.expect(body.idTokenValiditySeconds).to.eql(14400);",
+											"    pm.expect(body.domain).to.eql(pm.environment.get('domain'));",
+											"    pm.expect(body.enabled).to.eql(true);",
+											"    pm.expect(body.enhanceScopesWithUserPermissions).to.eql(false);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"clientId\": \"my-client\",\n  \"clientSecret\": \"my-client-secret\"\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Web application - authorization_code",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c37cba72-91c2-4850-80cd-6fd3908e406e",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"is webapp\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.expect(body).to.have.property('redirectUris');",
+											"    pm.expect(body).to.have.property('authorizedGrantTypes');",
+											"    pm.expect(body).to.have.property('responseTypes');",
+											"    pm.expect(body).to.have.property('applicationType');",
+											"",
+											"    pm.expect(body.redirectUris).to.eql(['https://callback']);",
+											"    pm.expect(body.authorizedGrantTypes).to.eql(['authorization_code']);",
+											"    pm.expect(body.responseTypes).to.eql(['code']);//default value",
+											"    pm.expect(body.applicationType).to.eql('web');//default value",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirectUris\": [\"https://callback\"],\n  \"authorizedGrantTypes\": [\"authorization_code\"],\n  \"scopes\": [\"openid\"]\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Single Page Application - Implicit",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c37cba72-91c2-4850-80cd-6fd3908e406e",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"is Single Page Application\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.expect(body).to.have.property('authorizedGrantTypes');",
+											"    pm.expect(body).to.have.property('responseTypes');",
+											"    pm.expect(body.authorizedGrantTypes).to.eql(['implicit']);",
+											"    pm.expect(body.responseTypes).to.eql(['token']);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirectUris\": [\"https://callback\"],\n  \"authorizedGrantTypes\": [\"implicit\"],\n  \"responseTypes\": [\"token\"],\n  \"scopes\": [\"openid\"]\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Mobile application - authorization_code",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c37cba72-91c2-4850-80cd-6fd3908e406e",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"is mobile\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.expect(body).to.have.property('redirectUris');",
+											"    pm.expect(body).to.have.property('authorizedGrantTypes');",
+											"    pm.expect(body).to.have.property('responseTypes');",
+											"    pm.expect(body).to.have.property('applicationType');",
+											"",
+											"    pm.expect(body.redirectUris).to.eql(['com.gravitee.app://callback']);",
+											"    pm.expect(body.authorizedGrantTypes).to.eql(['authorization_code','refresh_token']);",
+											"    pm.expect(body.responseTypes).to.eql(['code']);",
+											"    pm.expect(body.applicationType).to.eql('native');",
+											"    ",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirectUris\": [\"com.gravitee.app://callback\"],\n  \"authorizedGrantTypes\": [\"authorization_code\",\"refresh_token\"],\n  \"applicationType\": \"native\",\n  \"scopes\": [\"openid\"]\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Server application - client_credentials",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c37cba72-91c2-4850-80cd-6fd3908e406e",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"is server\", function () {",
+											"    var body = JSON.parse(responseBody);",
+											"    pm.expect(body).to.have.property('redirectUris');",
+											"    pm.expect(body).to.have.property('authorizedGrantTypes');",
+											"    pm.expect(body).to.have.property('responseTypes');",
+											"    pm.expect(body).to.have.property('applicationType');",
+											"",
+											"    pm.expect(body.redirectUris).to.eql([]);",
+											"    pm.expect(body.authorizedGrantTypes).to.eql(['client_credentials']);",
+											"    pm.expect(body.responseTypes).to.eql([]);",
+											"    pm.expect(body.applicationType).to.eql('server');",
+											"    ",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\"client_credentials\"],\n  \"responseTypes\": [],\n  \"applicationType\": \"server\",\n  \"scopes\": [\"openid\"]\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Delete client",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "fbe2362d-ad75-4baa-8825-b74218b047c7",
+										"exec": [
+											"pm.test(\"Status code is 204\", function () {",
+											"    pm.response.to.have.status(204);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "DELETE",
+								"header": [
+									{
+										"key": "Content-Type",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"value": "Bearer {{token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"clientId\": \"my-client\",\n  \"clientSecret\": \"my-client-secret\"\n}"
+								},
+								"url": {
+									"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
+									"host": [
+										"{{management_url}}"
+									],
+									"path": [
+										"management",
+										"domains",
+										"{{domain}}",
+										"clients",
+										"{{client}}"
+									]
+								}
+							},
+							"response": []
+						}
+					],
+					"_postman_isSubFolder": true
+				}
+			]
+		},
+		{
+			"name": "Delete domain",
+			"event": [
+				{
+					"listen": "test",
+					"script": {
+						"id": "abfa8366-3ee2-45b0-b658-0040b79d565c",
+						"exec": [
+							"pm.test(\"Status code is 204\", function () {",
+							"    pm.response.to.have.status(204);",
+							"});"
+						],
+						"type": "text/javascript"
+					}
+				}
+			],
+			"request": {
+				"method": "DELETE",
+				"header": [
+					{
+						"key": "Content-Type",
+						"value": "application/json"
+					},
+					{
+						"key": "Authorization",
+						"value": "Bearer {{token}}"
+					}
+				],
+				"body": {
+					"mode": "raw",
+					"raw": ""
+				},
+				"url": {
+					"raw": "{{management_url}}/management/domains/{{domain}}",
+					"host": [
+						"{{management_url}}"
+					],
+					"path": [
+						"management",
+						"domains",
+						"{{domain}}"
+					]
+				}
+			},
+			"response": []
+		}
+	]
+}
diff --git a/postman/collections/graviteeio-am-login-collection.json b/postman/collections/graviteeio-am-login-collection.json
index 160c5b17cc..b5d0fb04a8 100644
--- a/postman/collections/graviteeio-am-login-collection.json
+++ b/postman/collections/graviteeio-am-login-collection.json
@@ -248,7 +248,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\n    \"authorization_code\",\n    \"client_credentials\",\n    \"implicit\",\n    \"password\",\n    \"refresh_token\"\n  ],\n  \"scopes\": [\"openid\"],\n  \"accessTokenValiditySeconds\": 7200,\n  \"refreshTokenValiditySeconds\": 14400,\n  \"idTokenValiditySeconds\": 14400,\n  \"idTokenCustomClaims\": {},\n  \"enabled\": true,\n  \"identities\": [\n    \"{{idp.inmemory}}\"\n  ],\n  \"enhanceScopesWithUserPermissions\": false\n}"
+							"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\n    \"authorization_code\",\n    \"client_credentials\",\n    \"password\",\n    \"refresh_token\"\n  ],\n  \"scopes\": [\"openid\"],\n  \"accessTokenValiditySeconds\": 7200,\n  \"refreshTokenValiditySeconds\": 14400,\n  \"idTokenValiditySeconds\": 14400,\n  \"idTokenCustomClaims\": {},\n  \"enabled\": true,\n  \"identities\": [\n    \"{{idp.inmemory}}\"\n  ],\n  \"enhanceScopesWithUserPermissions\": false\n}"
 						},
 						"url": {
 							"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client}}",
@@ -801,4 +801,4 @@
 			"response": []
 		}
 	]
-}
\ No newline at end of file
+}
diff --git a/postman/collections/graviteeio-am-oauth2-collection.json b/postman/collections/graviteeio-am-oauth2-collection.json
index c397905cca..aa1fbfd45e 100644
--- a/postman/collections/graviteeio-am-oauth2-collection.json
+++ b/postman/collections/graviteeio-am-oauth2-collection.json
@@ -458,7 +458,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\n    \"authorization_code\",\n    \"client_credentials\",\n    \"implicit\",\n    \"password\",\n    \"refresh_token\"\n  ],\n  \"scopes\": [\"scope1\", \"openid\"],\n  \"accessTokenValiditySeconds\": 7200,\n  \"refreshTokenValiditySeconds\": 14400,\n  \"idTokenValiditySeconds\": 14400,\n  \"idTokenCustomClaims\": {},\n  \"enabled\": true,\n  \"identities\": [\n    \"{{idp.inmemory}}\"\n  ],\n  \"enhanceScopesWithUserPermissions\": false\n}"
+							"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\n    \"authorization_code\",\n    \"client_credentials\",\n    \"password\",\n    \"refresh_token\"\n  ],\n  \"scopes\": [\"scope1\", \"openid\"],\n  \"accessTokenValiditySeconds\": 7200,\n  \"refreshTokenValiditySeconds\": 14400,\n  \"idTokenValiditySeconds\": 14400,\n  \"idTokenCustomClaims\": {},\n  \"enabled\": true,\n  \"identities\": [\n    \"{{idp.inmemory}}\"\n  ],\n  \"enhanceScopesWithUserPermissions\": false\n}"
 						},
 						"url": {
 							"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client1}}",
@@ -12289,4 +12289,4 @@
 			"response": []
 		}
 	]
-}
\ No newline at end of file
+}
diff --git a/postman/collections/graviteeio-am-openid-core-collection.json b/postman/collections/graviteeio-am-openid-core-collection.json
index ecacfb6f68..197142d1df 100644
--- a/postman/collections/graviteeio-am-openid-core-collection.json
+++ b/postman/collections/graviteeio-am-openid-core-collection.json
@@ -402,7 +402,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "{\n  \"redirectUris\": [],\n  \"authorizedGrantTypes\": [\n    \"authorization_code\",\n    \"client_credentials\",\n    \"implicit\",\n    \"password\",\n    \"refresh_token\"\n  ],\n  \"scopes\": [\"scope1\", \"openid\"],\n  \"accessTokenValiditySeconds\": 7200,\n  \"refreshTokenValiditySeconds\": 14400,\n  \"idTokenValiditySeconds\": 14400,\n  \"idTokenCustomClaims\": {},\n  \"enabled\": true,\n  \"identities\": [\n    \"{{idp.inmemory}}\"\n  ],\n  \"enhanceScopesWithUserPermissions\": false\n}"
+							"raw": "{\n  \"redirectUris\": [\"https://domain/callback\",\"https://another/callback\"],\n  \"authorizedGrantTypes\": [\n    \"authorization_code\",\n    \"client_credentials\",\n    \"implicit\",\n    \"password\",\n    \"refresh_token\"\n  ],\n  \"scopes\": [\"scope1\", \"openid\"],\n  \"accessTokenValiditySeconds\": 7200,\n  \"refreshTokenValiditySeconds\": 14400,\n  \"idTokenValiditySeconds\": 14400,\n  \"idTokenCustomClaims\": {},\n  \"enabled\": true,\n  \"identities\": [\n    \"{{idp.inmemory}}\"\n  ],\n  \"enhanceScopesWithUserPermissions\": false\n}"
 						},
 						"url": {
 							"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{client1}}",
@@ -3025,7 +3025,7 @@
 													"    ",
 													"    tests['Redirect to error page'] = location.includes(pm.environment.get('gateway_url') + '/' + domain + '/oauth/error');",
 													"    tests['Contains an error query-parameter'] = location.includes('?error=invalid_request');",
-													"    tests['Contains an error description query-parameter'] = location.includes('error_description=A+redirect_uri+must+be+supplied');",
+													"    tests['Contains an error description query-parameter'] = location.includes('a+redirect_uri+must+be+supplied');",
 													"});"
 												],
 												"type": "text/javascript"
@@ -4704,7 +4704,7 @@
 													"    ",
 													"    tests['Redirect to error page'] = location.includes(pm.environment.get('gateway_url') + '/' + domain + '/oauth/error');",
 													"    tests['Contains an error query-parameter'] = location.includes('?error=invalid_request');",
-													"    tests['Contains an error description query-parameter'] = location.includes('error_description=A+redirect_uri+must+be+supplied');",
+													"    tests['Contains an error description query-parameter'] = location.includes('a+redirect_uri+must+be+supplied');",
 													"});"
 												],
 												"type": "text/javascript"
@@ -4824,4 +4824,4 @@
 			"response": []
 		}
 	]
-}
\ No newline at end of file
+}
diff --git a/postman/collections/graviteeio-am-openid-dcr-collection.json b/postman/collections/graviteeio-am-openid-dcr-collection.json
index 9c888220d6..c81c6701e3 100644
--- a/postman/collections/graviteeio-am-openid-dcr-collection.json
+++ b/postman/collections/graviteeio-am-openid-dcr-collection.json
@@ -135,7 +135,7 @@
 							"script": {
 								"id": "2e92f1ea-5d06-4aa3-9ddc-95b0359a8f20",
 								"exec": [
-									"pm.test(\"Status code is 201\", function () {",
+									"pm.test(\"Status code is 204\", function () {",
 									"    pm.response.to.have.status(204);",
 									"});"
 								],
@@ -255,6 +255,10 @@
 								"value": "Bearer {{token}}"
 							}
 						],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
 						"url": {
 							"raw": "{{management_url}}/management/domains/{{domain}}/certificates",
 							"host": [
@@ -514,6 +518,10 @@
 					"request": {
 						"method": "GET",
 						"header": [],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
 						"url": {
 							"raw": "{{gateway_url}}/{{domain}}/oidc/.well-known/openid-configuration",
 							"host": [
@@ -657,6 +665,9 @@
 									"pm.test(\"Has default attributes\", function () {",
 									"    var body = pm.response.json();",
 									"    pm.expect(body.client_name).to.eql('open_dcr_client');",
+									"    pm.expect(body.application_type).to.eql('web');",
+									"    pm.expect(body.grant_types[0]).to.eql('authorization_code');",
+									"    pm.expect(body.response_types[0]).to.eql('code');",
 									"    ",
 									"    pm.environment.set('newClientForDCRTests', body.id);",
 									"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
@@ -678,7 +689,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "{\n   \"client_name\": \"open_dcr_client\",\t\n   \"application_type\": \"web\",\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"subject_type\": \"public\",\n\t\"response_types\": [\"token\", \"code\", \"code token\"],\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+							"raw": "{\n   \"client_name\": \"open_dcr_client\",\t\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"subject_type\": \"public\",\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 						},
 						"url": {
 							"raw": "{{registrationEndpoint}}",
@@ -706,8 +717,8 @@
 									"    var body = pm.response.json();",
 									"    pm.expect(body).to.have.property(\"redirect_uris\");",
 									"    pm.expect(body).to.have.property(\"grant_types\");",
-									"    pm.expect(body.response_types).to.eql([ 'token','code','code token' ]);",
-									"    pm.expect(body.grant_types).to.eql([ 'implicit','authorization_code' ]);",
+									"    pm.expect(body.response_types).to.eql([ 'code' ]);//default value",
+									"    pm.expect(body.grant_types).to.eql([ 'authorization_code' ]);//default value",
 									"    ",
 									"    //The Authorization Server need not include the registration_access_token or registration_client_uri value in this response unless they have been updated.",
 									"    pm.expect(body).to.not.have.property('registration_access_token');",
@@ -732,6 +743,10 @@
 								"value": "Bearer {{registrationAccessToken}}"
 							}
 						],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
 						"url": {
 							"raw": "{{registrationClientUri}}",
 							"host": [
@@ -759,6 +774,8 @@
 									"    pm.expect(body.client_name).to.eql('Client patched via DCR');",
 									"    pm.expect(body).to.have.property(\"response_types\");",
 									"    pm.expect(body.response_types).to.eql(['token', 'code', 'code id_token']);",
+									"    pm.expect(body).to.have.property(\"grant_types\");",
+									"    pm.expect(body.grant_types).to.eql(['implicit', 'authorization_code']);",
 									"});",
 									"",
 									"pm.test(\"One time Token\", function() {",
@@ -818,6 +835,8 @@
 									"    pm.expect(body.client_name).to.eql('Client name updated via DCR');",
 									"    pm.expect(body).to.have.property(\"response_types\");",
 									"    pm.expect(body.response_types).to.eql(['code']);",
+									"    pm.expect(body).to.have.property(\"grant_types\");",
+									"    pm.expect(body.grant_types).to.eql(['authorization_code']);",
 									"});",
 									"",
 									"pm.test(\"One time Token\", function() {",
@@ -1056,7 +1075,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "{\n  \"authorizedGrantTypes\": [\"client_credentials\"]\n}"
+							"raw": "{\n  \"authorizedGrantTypes\": [\"client_credentials\"],\n  \"responseTypes\": [],\n  \"applicationType\": \"server\"\n}"
 						},
 						"url": {
 							"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{clientDCR}}",
@@ -1419,6 +1438,206 @@
 							},
 							"response": []
 						},
+						{
+							"name": "Invalid redirect uri - null - implicit grant",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Redirect uris are missing\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('Missing or invalid redirect_uris.');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirect_uris\": null,\n  \"grant_types\": [\"implicit\"],\n  \"response_types\": [\"token\"],\n  \"client_name\": \"My implicit Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationEndpoint}}",
+									"host": [
+										"{{registrationEndpoint}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Invalid redirect uri - empty - implicit grant",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Redirect uris are missing\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('Missing or invalid redirect_uris.');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirect_uris\": [],\n  \"grant_types\": [\"implicit\"],\n  \"response_types\": [\"token\"],\n  \"client_name\": \"My implicit Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationEndpoint}}",
+									"host": [
+										"{{registrationEndpoint}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Invalid redirect uri - no scheme uri",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Redirect uris localhost forbidden\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('redirect_uri : no_scheme is malformed');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirect_uris\": [\"no_scheme\"],\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationEndpoint}}",
+									"host": [
+										"{{registrationEndpoint}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Invalid redirect uri - malformed uri",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Redirect uris localhost forbidden\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('redirect_uri : malformed:uri:exception is malformed');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirect_uris\": [\"malformed:uri:exception\"],\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationEndpoint}}",
+									"host": [
+										"{{registrationEndpoint}}"
+									]
+								}
+							},
+							"response": []
+						},
 						{
 							"name": "Invalid redirect uri - localhost",
 							"event": [
@@ -1670,12 +1889,12 @@
 							"response": []
 						},
 						{
-							"name": "Invalid subject type",
+							"name": "Invalid grant type - empty",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
-										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
 										"exec": [
 											"pm.test(\"Status code is 400\", function () {",
 											"    pm.response.to.have.status(400);",
@@ -1685,7 +1904,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported subject type');",
+											"    pm.expect(body.error_description).to.eql('Missing or invalid grant type.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -1708,7 +1927,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n   \"application_type\": \"web\",\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"subject_type\": \"pairwise\",\n   \"token_endpoint_auth_method\": \"client_secret_basic\",\n   \"userinfo_encrypted_response_alg\": \"RSA1_5\",\n   \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"grant_types\": [],\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\",\n  \"jwks_uri\": \"https://client.example.org/my_public_keys.jwks\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -1720,12 +1939,12 @@
 							"response": []
 						},
 						{
-							"name": "Invalid userinfo signing algorithm",
+							"name": "Invalid grant type - refresh_token alone",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
-										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
 										"exec": [
 											"pm.test(\"Status code is 400\", function () {",
 											"    pm.response.to.have.status(400);",
@@ -1735,7 +1954,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported userinfo signing algorithm');",
+											"    pm.expect(body.error_description).to.include('refresh_token grant type must be associated with one of');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -1758,7 +1977,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"userinfo_signed_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n  \"redirect_uris\": [],\n  \"response_types\": [],\n  \"grant_types\": [\"refresh_token\"],\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -1770,7 +1989,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid userinfo response alg",
+							"name": "Invalid subject type",
 							"event": [
 								{
 									"listen": "test",
@@ -1785,7 +2004,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported userinfo_encrypted_response_alg value');",
+											"    pm.expect(body.error_description).to.eql('Unsupported subject type');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -1808,7 +2027,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"userinfo_encrypted_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n   \"application_type\": \"web\",\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"subject_type\": \"pairwise\",\n   \"token_endpoint_auth_method\": \"client_secret_basic\",\n   \"userinfo_encrypted_response_alg\": \"RSA1_5\",\n   \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -1820,7 +2039,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid userinfo response enc",
+							"name": "Invalid userinfo signing algorithm",
 							"event": [
 								{
 									"listen": "test",
@@ -1835,7 +2054,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported userinfo_encrypted_response_enc value');",
+											"    pm.expect(body.error_description).to.eql('Unsupported userinfo signing algorithm');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -1858,7 +2077,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"userinfo_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"userinfo_encrypted_response_enc\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"userinfo_signed_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -1870,7 +2089,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid id_token signing algorithm",
+							"name": "Invalid userinfo response alg",
 							"event": [
 								{
 									"listen": "test",
@@ -1885,7 +2104,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported id_token signing algorithm');",
+											"    pm.expect(body.error_description).to.eql('Unsupported userinfo_encrypted_response_alg value');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -1908,7 +2127,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_signed_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"userinfo_encrypted_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -1920,7 +2139,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid id_token response alg",
+							"name": "Invalid userinfo response enc",
 							"event": [
 								{
 									"listen": "test",
@@ -1935,7 +2154,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_alg value');",
+											"    pm.expect(body.error_description).to.eql('Unsupported userinfo_encrypted_response_enc value');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -1958,7 +2177,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_encrypted_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"userinfo_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"userinfo_encrypted_response_enc\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -1970,7 +2189,7 @@
 							"response": []
 						},
 						{
-							"name": "Missing id_token response alg",
+							"name": "Invalid id_token signing algorithm",
 							"event": [
 								{
 									"listen": "test",
@@ -1985,7 +2204,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('When id_token_encrypted_response_enc is included, id_token_encrypted_response_alg MUST also be provided');",
+											"    pm.expect(body.error_description).to.eql('Unsupported id_token signing algorithm');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2008,7 +2227,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_encrypted_response_enc\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_signed_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -2020,7 +2239,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid id_token response enc",
+							"name": "Invalid id_token response alg",
 							"event": [
 								{
 									"listen": "test",
@@ -2035,7 +2254,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_enc value');",
+											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_alg value');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2058,7 +2277,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"id_token_encrypted_response_enc\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_encrypted_response_alg\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -2070,22 +2289,22 @@
 							"response": []
 						},
 						{
-							"name": "Invalid request uri",
+							"name": "Missing id_token response alg",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
-										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
 										"exec": [
 											"pm.test(\"Status code is 400\", function () {",
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid request uri\", function () {",
+											"pm.test(\"Invalid grant type\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('request_uris: malformed_url is not valid.');",
+											"    pm.expect(body.error_description).to.eql('When id_token_encrypted_response_enc is included, id_token_encrypted_response_alg MUST also be provided');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2108,7 +2327,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"request_uris\": [\n\t\"malformed_url\"\n   ],\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\",\n  \"jwks_uri\": \"https://client.example.org/my_public_keys.jwks\"\n}"
+									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_encrypted_response_enc\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -2120,22 +2339,22 @@
 							"response": []
 						},
 						{
-							"name": "Invalid scope",
+							"name": "Invalid id_token response enc",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
-										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
 										"exec": [
 											"pm.test(\"Status code is 400\", function () {",
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid scope\", function () {",
+											"pm.test(\"Invalid grant type\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('scope unkown-domain-scope is not valid.');",
+											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_enc value');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2158,7 +2377,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"scope\": \"unkown-domain-scope\",\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
+									"raw": "{\n\t\"application_type\": \"web\",\n\t\"redirect_uris\": [\n\t\t\"https://client.example.org/callback\",\n\t\t\"https://client.example.org/callback2\"\n\t],\n\t\"logo_uri\": \"https://client.example.org/logo.png\",\n\t\"token_endpoint_auth_method\": \"client_secret_basic\",\n\t\"id_token_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"id_token_encrypted_response_enc\":\"unknown\",\n\t\"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n\t\"request_uris\": [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -2170,7 +2389,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid jwks",
+							"name": "Invalid request uri",
 							"event": [
 								{
 									"listen": "test",
@@ -2181,11 +2400,11 @@
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid scope\", function () {",
+											"pm.test(\"Invalid request uri\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.include('Unable to parse jwks content');",
+											"    pm.expect(body.error_description).to.eql('request_uris: malformed_url is not valid.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2208,7 +2427,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"client_name\": \"My Example Client\",\n   \"jwks\": {\n        \"keys\": [\n\t\t\t{  \n\t\t\t\t\"kty\":\"EC\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"crv\":\"P-521\",\n                \"kid\": \"elliptic-curve-encryption\",\n\t\t\t\t\"x\":\"l3X_aK4GSyoZ9TV8XXM9D3BaowFI4AQtrQyU39DWzxU\",\n\t\t\t\t\"y\":\"2J7zifgjRhLV7B-MPYVqIB-X1bLQAyVXvZmc9LTpcXM\"\n\t\t\t}\n        ]\n    }\n}"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"request_uris\": [\n\t\"malformed_url\"\n   ],\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\",\n  \"jwks_uri\": \"https://client.example.org/my_public_keys.jwks\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -2218,63 +2437,24 @@
 								}
 							},
 							"response": []
-						}
-					],
-					"event": [
-						{
-							"listen": "prerequest",
-							"script": {
-								"id": "6344fd45-5776-4bab-a90c-033893e6debb",
-								"type": "text/javascript",
-								"exec": [
-									""
-								]
-							}
 						},
 						{
-							"listen": "test",
-							"script": {
-								"id": "03904ca6-6d82-43ab-8190-f3210787a262",
-								"type": "text/javascript",
-								"exec": [
-									""
-								]
-							}
-						}
-					],
-					"_postman_isSubFolder": true
-				},
-				{
-					"name": "Invalid update requests",
-					"item": [
-						{
-							"name": "Register client",
+							"name": "Invalid scope",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
-										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
 										"exec": [
-											"pm.test(\"Status code is 201\", function () {",
-											"    pm.response.to.have.status(201);",
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Has default attributes\", function () {",
+											"pm.test(\"Invalid scope\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
-											"    pm.expect(body).to.have.property('response_types');",
-											"    pm.expect(body).to.have.property('grant_types');",
-											"    pm.expect(body).to.have.property('scope');",
-											"    pm.expect(body).to.have.property('client_name');",
-											"    pm.expect(body).to.have.property('client_id');",
-											"    pm.expect(body).to.have.property('client_secret');",
-											"    pm.expect(body.response_types).to.eql(['code']);",
-											"    pm.expect(body.grant_types).to.eql(['authorization_code']);",
-											"    pm.expect(body.scope).to.eql('openid');",
-											"    pm.expect(body.client_name).to.eql('Unknown Client');",
-											"    ",
-											"    pm.environment.set('newClientForDCRTests', body.id);",
-											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
-											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
+											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
+											"    pm.expect(body.error_description).to.eql('scope unkown-domain-scope is not valid.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2297,7 +2477,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n   \"application_type\": \"web\",\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"token_endpoint_auth_method\": \"client_secret_basic\",\n   \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\",\n   \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"scope\": \"unkown-domain-scope\",\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -2309,22 +2489,22 @@
 							"response": []
 						},
 						{
-							"name": "Invalid access token",
+							"name": "Invalid jwks",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
-										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"id": "c557fd6b-d770-4568-8db7-ccb3267b0256",
 										"exec": [
-											"pm.test(\"Status code is 401\", function () {",
-											"    pm.response.to.have.status(401);",
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid bearer\", function () {",
+											"pm.test(\"Invalid scope\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
-											"    pm.expect(body.error).to.eql('invalid_token');",
-											"    pm.expect(body.error_description).to.eql('The access token is invalid');",
+											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
+											"    pm.expect(body.error_description).to.include('Unable to parse jwks content');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2332,7 +2512,7 @@
 								}
 							],
 							"request": {
-								"method": "PUT",
+								"method": "POST",
 								"header": [
 									{
 										"key": "Content-Type",
@@ -2342,39 +2522,76 @@
 									{
 										"key": "Authorization",
 										"type": "text",
-										"value": "Bearer wrongToken"
+										"value": "Bearer {{access_token}}"
 									}
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"client_name\": \"My Example Client\",\n   \"jwks\": {\n        \"keys\": [\n\t\t\t{  \n\t\t\t\t\"kty\":\"EC\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"crv\":\"P-521\",\n                \"kid\": \"elliptic-curve-encryption\",\n\t\t\t\t\"x\":\"l3X_aK4GSyoZ9TV8XXM9D3BaowFI4AQtrQyU39DWzxU\",\n\t\t\t\t\"y\":\"2J7zifgjRhLV7B-MPYVqIB-X1bLQAyVXvZmc9LTpcXM\"\n\t\t\t}\n        ]\n    }\n}"
 								},
 								"url": {
-									"raw": "{{registrationClientUri}}",
+									"raw": "{{registrationEndpoint}}",
 									"host": [
-										"{{registrationClientUri}}"
+										"{{registrationEndpoint}}"
 									]
 								}
 							},
 							"response": []
+						}
+					],
+					"event": [
+						{
+							"listen": "prerequest",
+							"script": {
+								"id": "6344fd45-5776-4bab-a90c-033893e6debb",
+								"type": "text/javascript",
+								"exec": [
+									""
+								]
+							}
 						},
 						{
-							"name": "Invalid redirect uri",
+							"listen": "test",
+							"script": {
+								"id": "03904ca6-6d82-43ab-8190-f3210787a262",
+								"type": "text/javascript",
+								"exec": [
+									""
+								]
+							}
+						}
+					],
+					"_postman_isSubFolder": true
+				},
+				{
+					"name": "Invalid update requests",
+					"item": [
+						{
+							"name": "Register client",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
 										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
 										"exec": [
-											"pm.test(\"Status code is 400\", function () {",
-											"    pm.response.to.have.status(400);",
+											"pm.test(\"Status code is 201\", function () {",
+											"    pm.response.to.have.status(201);",
 											"});",
 											"",
-											"pm.test(\"Redirect uris are missing\", function () {",
-											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"pm.test(\"Has default attributes\", function () {",
 											"    var body = pm.response.json();",
-											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
-											"    pm.expect(body.error_description).to.eql('Missing or invalid redirect_uris.');",
+											"    pm.expect(body).to.have.property('response_types');",
+											"    pm.expect(body).to.have.property('grant_types');",
+											"    pm.expect(body).to.have.property('client_name');",
+											"    pm.expect(body).to.have.property('client_id');",
+											"    pm.expect(body).to.have.property('client_secret');",
+											"    pm.expect(body.response_types).to.eql(['code']);",
+											"    pm.expect(body.grant_types).to.eql(['authorization_code']);",
+											"    pm.expect(body.client_name).to.eql('Unknown Client');",
+											"    ",
+											"    pm.environment.set('newClientForDCRTests', body.id);",
+											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
+											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2382,7 +2599,7 @@
 								}
 							],
 							"request": {
-								"method": "PUT",
+								"method": "POST",
 								"header": [
 									{
 										"key": "Content-Type",
@@ -2392,39 +2609,39 @@
 									{
 										"key": "Authorization",
 										"type": "text",
-										"value": "Bearer {{registrationAccessToken}}"
+										"value": "Bearer {{access_token}}"
 									}
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n   \"client_name\": \"Should have not been updated\"\n}\n"
+									"raw": "{\n   \"application_type\": \"web\",\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"token_endpoint_auth_method\": \"client_secret_basic\",\n   \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\",\n   \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
 								},
 								"url": {
-									"raw": "{{registrationClientUri}}",
+									"raw": "{{registrationEndpoint}}",
 									"host": [
-										"{{registrationClientUri}}"
+										"{{registrationEndpoint}}"
 									]
 								}
 							},
 							"response": []
 						},
 						{
-							"name": "Invalid redirect uri - localhost",
+							"name": "Invalid access token",
 							"event": [
 								{
 									"listen": "test",
 									"script": {
 										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
 										"exec": [
-											"pm.test(\"Status code is 400\", function () {",
-											"    pm.response.to.have.status(400);",
+											"pm.test(\"Status code is 401\", function () {",
+											"    pm.response.to.have.status(401);",
 											"});",
 											"",
-											"pm.test(\"Redirect uris localhost forbidden\", function () {",
+											"pm.test(\"Invalid bearer\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
-											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
-											"    pm.expect(body.error_description).to.eql('localhost is forbidden');",
+											"    pm.expect(body.error).to.eql('invalid_token');",
+											"    pm.expect(body.error_description).to.eql('The access token is invalid');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2442,12 +2659,12 @@
 									{
 										"key": "Authorization",
 										"type": "text",
-										"value": "Bearer {{registrationAccessToken}}"
+										"value": "Bearer wrongToken"
 									}
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{  \"redirect_uris\": [\n    \"https://localhost/callback\",\n    \"https://localhost/callback2\"\n   ],\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n   \"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2459,7 +2676,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid response type",
+							"name": "Invalid redirect uri",
 							"event": [
 								{
 									"listen": "test",
@@ -2470,11 +2687,11 @@
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid response type\", function () {",
+											"pm.test(\"Redirect uris are missing\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
-											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Invalid response type.');",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('Missing or invalid redirect_uris.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2497,7 +2714,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"response_types\": [\n\t\"unknown\"\n   ],\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n   \"client_name\": \"Should have not been updated\"\n}\n"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2509,7 +2726,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid grant type",
+							"name": "Invalid redirect uri - can not be empty",
 							"event": [
 								{
 									"listen": "test",
@@ -2520,11 +2737,11 @@
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid grant type\", function () {",
+											"pm.test(\"Redirect uris are missing\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
-											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Missing or invalid grant type.');",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('Missing or invalid redirect_uris.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2532,7 +2749,7 @@
 								}
 							],
 							"request": {
-								"method": "PUT",
+								"method": "PATCH",
 								"header": [
 									{
 										"key": "Content-Type",
@@ -2547,7 +2764,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"grant_types\": [\n\t\"unknown\"\n   ],\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n   \"client_name\": \"Client with implicit flow should not allow empty redirect_uris\",\n   \"grant_types\": [\"implicit\"],\n   \"response_types\": [\"token\"],\n   \"redirect_uris\": []\n}\n"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2559,7 +2776,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid subject  type",
+							"name": "Invalid redirect uri - localhost",
 							"event": [
 								{
 									"listen": "test",
@@ -2570,11 +2787,11 @@
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid grant type\", function () {",
+											"pm.test(\"Redirect uris localhost forbidden\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
-											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported subject type');",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('localhost is forbidden');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2597,7 +2814,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"subject_type\": \"pairwise\",\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{  \"redirect_uris\": [\n    \"https://localhost/callback\",\n    \"https://localhost/callback2\"\n   ],\n   \"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2609,7 +2826,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid userinfo signing algorithm",
+							"name": "Invalid response type",
 							"event": [
 								{
 									"listen": "test",
@@ -2624,7 +2841,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported userinfo signing algorithm');",
+											"    pm.expect(body.error_description).to.eql('Invalid response type.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2647,7 +2864,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"userinfo_signed_response_alg\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"response_types\": [\n\t\"unknown\"\n   ],\n   \"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2659,7 +2876,7 @@
 							"response": []
 						},
 						{
-							"name": "Missing userinfo response alg",
+							"name": "Invalid grant type",
 							"event": [
 								{
 									"listen": "test",
@@ -2674,7 +2891,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('When userinfo_encrypted_response_enc is included, userinfo_encrypted_response_alg MUST also be provided');",
+											"    pm.expect(body.error_description).to.eql('Missing or invalid grant type.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2692,12 +2909,12 @@
 									{
 										"key": "Authorization",
 										"type": "text",
-										"value": "Bearer {{access_token}}"
+										"value": "Bearer {{registrationAccessToken}}"
 									}
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"userinfo_encrypted_response_enc\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n  \"grant_types\": [\n\t\"unknown\"\n   ],\n   \"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2709,7 +2926,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid userinfo response enc",
+							"name": "Invalid grant type - refresh_token alone",
 							"event": [
 								{
 									"listen": "test",
@@ -2724,7 +2941,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported userinfo_encrypted_response_enc value');",
+											"    pm.expect(body.error_description).to.include('refresh_token grant type must be associated with one of');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2742,12 +2959,12 @@
 									{
 										"key": "Authorization",
 										"type": "text",
-										"value": "Bearer {{access_token}}"
+										"value": "Bearer {{registrationAccessToken}}"
 									}
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"redirect_uris\": [\n    \t\"https://client.example.org/callback\",\n    \t\"https://client.example.org/callback2\"],\n\t\"userinfo_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"userinfo_encrypted_response_enc\":\"unknown\",\n\t\"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n  \"redirect_uris\": [],\n  \"response_types\": [],\n  \"grant_types\": [\"refresh_token\"],\n  \"client_name\": \"My Example Client\",\n  \"token_endpoint_auth_method\": \"client_secret_basic\",\n  \"logo_uri\": \"https://client.example.org/logo.png\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2759,7 +2976,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid id_token signing algorithm",
+							"name": "Invalid subject  type",
 							"event": [
 								{
 									"listen": "test",
@@ -2770,11 +2987,11 @@
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid response type\", function () {",
+											"pm.test(\"Invalid grant type\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported id_token signing algorithm');",
+											"    pm.expect(body.error_description).to.eql('Unsupported subject type');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2797,7 +3014,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"id_token_signed_response_alg\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"subject_type\": \"pairwise\",\n   \"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2809,7 +3026,7 @@
 							"response": []
 						},
 						{
-							"name": "Missing id_token response alg",
+							"name": "Invalid userinfo signing algorithm",
 							"event": [
 								{
 									"listen": "test",
@@ -2820,11 +3037,11 @@
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid grant type\", function () {",
+											"pm.test(\"Invalid response type\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('When id_token_encrypted_response_enc is included, id_token_encrypted_response_alg MUST also be provided');",
+											"    pm.expect(body.error_description).to.eql('Unsupported userinfo signing algorithm');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2842,12 +3059,12 @@
 									{
 										"key": "Authorization",
 										"type": "text",
-										"value": "Bearer {{access_token}}"
+										"value": "Bearer {{registrationAccessToken}}"
 									}
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"id_token_encrypted_response_enc\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"userinfo_signed_response_alg\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2859,7 +3076,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid id_token response alg",
+							"name": "Missing userinfo response alg",
 							"event": [
 								{
 									"listen": "test",
@@ -2874,7 +3091,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_alg value');",
+											"    pm.expect(body.error_description).to.eql('When userinfo_encrypted_response_enc is included, userinfo_encrypted_response_alg MUST also be provided');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2897,7 +3114,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"id_token_encrypted_response_alg\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"userinfo_encrypted_response_enc\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2909,7 +3126,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid id_token response enc",
+							"name": "Invalid userinfo response enc",
 							"event": [
 								{
 									"listen": "test",
@@ -2924,7 +3141,7 @@
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_enc value');",
+											"    pm.expect(body.error_description).to.eql('Unsupported userinfo_encrypted_response_enc value');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -2947,7 +3164,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"redirect_uris\": [\n    \t\"https://client.example.org/callback\",\n    \t\"https://client.example.org/callback2\"],\n\t\"id_token_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"id_token_encrypted_response_enc\":\"unknown\",\n\t\"client_name\": \"Should have not been updated\"\n}"
+									"raw": "{\n\t\"redirect_uris\": [\n    \t\"https://client.example.org/callback\",\n    \t\"https://client.example.org/callback2\"],\n\t\"userinfo_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"userinfo_encrypted_response_enc\":\"unknown\",\n\t\"client_name\": \"Should have not been updated\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationClientUri}}",
@@ -2959,7 +3176,7 @@
 							"response": []
 						},
 						{
-							"name": "Invalid scope",
+							"name": "Invalid id_token signing algorithm",
 							"event": [
 								{
 									"listen": "test",
@@ -2970,11 +3187,211 @@
 											"    pm.response.to.have.status(400);",
 											"});",
 											"",
-											"pm.test(\"Invalid scope\", function () {",
+											"pm.test(\"Invalid response type\", function () {",
 											"    pm.response.to.be.header('Content-Type', 'application/json');",
 											"    var body = pm.response.json();",
 											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
-											"    pm.expect(body.error_description).to.eql('scope unkown-domain-scope is not valid.');",
+											"    pm.expect(body.error_description).to.eql('Unsupported id_token signing algorithm');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"id_token_signed_response_alg\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Missing id_token response alg",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Invalid grant type\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
+											"    pm.expect(body.error_description).to.eql('When id_token_encrypted_response_enc is included, id_token_encrypted_response_alg MUST also be provided');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"id_token_encrypted_response_enc\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Invalid id_token response alg",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Invalid grant type\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
+											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_alg value');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"redirect_uris\": [\n    \"https://client.example.org/callback\",\n    \"https://client.example.org/callback2\"],\n   \"id_token_encrypted_response_alg\":\"unknown\",\n   \"client_name\": \"Should have not been updated\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Invalid id_token response enc",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Invalid grant type\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
+											"    pm.expect(body.error_description).to.eql('Unsupported id_token_encrypted_response_enc value');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n\t\"redirect_uris\": [\n    \t\"https://client.example.org/callback\",\n    \t\"https://client.example.org/callback2\"],\n\t\"id_token_encrypted_response_alg\":\"RSA-OAEP-256\",\n\t\"id_token_encrypted_response_enc\":\"unknown\",\n\t\"client_name\": \"Should have not been updated\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Invalid scope",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Invalid scope\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_client_metadata');",
+											"    pm.expect(body.error_description).to.eql('scope unkown-domain-scope is not valid.');",
 											"});"
 										],
 										"type": "text/javascript"
@@ -3057,354 +3474,640 @@
 				}
 			]
 		},
-		{
-			"name": "Case - Nominal",
-			"item": [
-				{
-					"name": "Register client",
-					"event": [
-						{
-							"listen": "test",
-							"script": {
-								"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
-								"exec": [
-									"pm.test(\"Status code is 201\", function () {",
-									"    pm.response.to.have.status(201);",
-									"});",
-									"",
-									"pm.test(\"Has default attributes\", function () {",
-									"    var body = pm.response.json();",
-									"    pm.expect(body).to.have.property('response_types');",
-									"    pm.expect(body).to.have.property('grant_types');",
-									"    pm.expect(body).to.have.property('scope');",
-									"    pm.expect(body).to.have.property('client_name');",
-									"    pm.expect(body).to.have.property('client_id');",
-									"    pm.expect(body).to.have.property('client_secret');",
-									"    pm.expect(body.response_types).to.eql(['code']);",
-									"    pm.expect(body.grant_types).to.eql(['authorization_code']);",
-									"    pm.expect(body.scope).to.eql('openid');",
-									"    pm.expect(body.client_name).to.eql('Unknown Client');",
-									"    ",
-									"    pm.environment.set('newClientForDCRTests', body.id);",
-									"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
-									"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
-									"});"
-								],
-								"type": "text/javascript"
-							}
-						}
-					],
-					"request": {
-						"method": "POST",
-						"header": [
-							{
-								"key": "Content-Type",
-								"type": "text",
-								"value": "application/json"
-							},
-							{
-								"key": "Authorization",
-								"type": "text",
-								"value": "Bearer {{access_token}}"
-							}
-						],
-						"body": {
-							"mode": "raw",
-							"raw": "{\n   \"application_type\": \"web\",\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"subject_type\": \"public\",\n   \"token_endpoint_auth_method\": \"client_secret_basic\",\n   \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\",\n   \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
-						},
-						"url": {
-							"raw": "{{registrationEndpoint}}",
-							"host": [
-								"{{registrationEndpoint}}"
-							]
-						}
-					},
-					"response": []
-				},
-				{
-					"name": "Patch client",
-					"event": [
-						{
-							"listen": "test",
-							"script": {
-								"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
-								"exec": [
-									"pm.test(\"Status code is 200\", function () {",
-									"    pm.response.to.have.status(200);",
-									"});",
-									"",
-									"pm.test(\"Patch client with response types\", function () {",
-									"    pm.response.to.be.header('Content-Type', 'application/json');",
-									"    var body = pm.response.json();",
-									"    pm.expect(body).to.have.property(\"responseTypes\");",
-									"    pm.expect(body).to.have.property(\"authorizedGrantTypes\");",
-									"    pm.expect(body.responseTypes).to.eql(['token', 'code', 'code token']);",
-									"    pm.expect(body.authorizedGrantTypes).to.eql([ 'implicit', 'authorization_code' ]);",
-									"});",
-									"",
-									"// wait for sync process",
-									"setTimeout(function(){}, 5000);"
-								],
-								"type": "text/javascript"
-							}
-						}
-					],
-					"request": {
-						"method": "PATCH",
-						"header": [
-							{
-								"key": "Content-Type",
-								"type": "text",
-								"value": "application/json"
-							},
-							{
-								"key": "Authorization",
-								"type": "text",
-								"value": "Bearer {{token}}"
-							}
-						],
-						"body": {
-							"mode": "raw",
-							"raw": "{\n   \"responseTypes\": [\"token\", \"code\", \"code token\"],\n   \"clientName\": \"Client was created via DCR\"\n  }"
-						},
-						"url": {
-							"raw": "{{management_url}}/management/domains/{{domain}}/clients/{{newClientForDCRTests}}",
-							"host": [
-								"{{management_url}}"
-							],
-							"path": [
-								"management",
-								"domains",
-								"{{domain}}",
-								"clients",
-								"{{newClientForDCRTests}}"
-							]
-						}
-					},
-					"response": []
-				},
-				{
-					"name": "Get client - with registration token",
-					"event": [
-						{
-							"listen": "test",
-							"script": {
-								"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
-								"exec": [
-									"pm.test(\"Status code is 200\", function () {",
-									"    pm.response.to.have.status(200);",
-									"});",
-									"",
-									"pm.test(\"Get client with response types\", function () {",
-									"    pm.response.to.be.header('Content-Type', 'application/json');",
-									"    var body = pm.response.json();",
-									"    pm.expect(body).to.have.property(\"redirect_uris\");",
-									"    pm.expect(body).to.have.property(\"grant_types\");",
-									"    pm.expect(body.response_types).to.eql([ 'token','code','code token' ]);",
-									"    pm.expect(body.grant_types).to.eql([ 'implicit','authorization_code' ]);",
-									"    pm.expect(body.client_name).to.eql('Client was created via DCR');",
-									"    ",
-									"    //The Authorization Server need not include the registration_access_token or registration_client_uri value in this response unless they have been updated.",
-									"    pm.expect(body).to.not.have.property('registration_access_token');",
-									"    pm.expect(body).to.not.have.property('registration_client_uri');",
-									"});"
-								],
-								"type": "text/javascript"
-							}
-						}
-					],
-					"request": {
-						"method": "GET",
-						"header": [
-							{
-								"key": "Content-Type",
-								"type": "text",
-								"value": "application/json"
-							},
-							{
-								"key": "Authorization",
-								"type": "text",
-								"value": "Bearer {{registrationAccessToken}}"
-							}
-						],
-						"url": {
-							"raw": "{{registrationClientUri}}",
-							"host": [
-								"{{registrationClientUri}}"
-							]
-						}
-					},
-					"response": []
-				},
-				{
-					"name": "Patch client - with registration token",
-					"event": [
-						{
-							"listen": "test",
-							"script": {
-								"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
-								"exec": [
-									"pm.test(\"Status code is 200\", function () {",
-									"    pm.response.to.have.status(200);",
-									"});",
-									"",
-									"pm.test(\"Get client with response types\", function () {",
-									"    pm.response.to.be.header('Content-Type', 'application/json');",
-									"    var body = pm.response.json();",
-									"    pm.expect(body.client_name).to.eql('Client patched via DCR');",
-									"    pm.expect(body).to.have.property(\"response_types\");",
-									"    pm.expect(body.response_types).to.eql(['token', 'code', 'code id_token']);",
-									"});",
-									"",
-									"pm.test(\"One time Token\", function() {",
-									"    var body = pm.response.json();",
-									"    pm.expect(body).to.have.property('registration_access_token');",
-									"    pm.expect(body.registration_access_token).to.not.eql(pm.environment.get('registrationAccessToken'));",
-									"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
-									"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
-									"});"
-								],
-								"type": "text/javascript"
-							}
-						}
-					],
-					"request": {
-						"method": "PATCH",
-						"header": [
-							{
-								"key": "Content-Type",
-								"type": "text",
-								"value": "application/json"
-							},
-							{
-								"key": "Authorization",
-								"type": "text",
-								"value": "Bearer {{registrationAccessToken}}"
-							}
-						],
-						"body": {
-							"mode": "raw",
-							"raw": "{\n   \"client_name\": \"Client patched via DCR\",\n   \"response_types\" : [\"token\", \"code\", \"code id_token\"]\n}"
-						},
-						"url": {
-							"raw": "{{registrationClientUri}}",
-							"host": [
-								"{{registrationClientUri}}"
-							]
-						}
-					},
-					"response": []
-				},
-				{
-					"name": "Update client - with registration token",
-					"event": [
-						{
-							"listen": "test",
-							"script": {
-								"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
-								"exec": [
-									"pm.test(\"Status code is 200\", function () {",
-									"    pm.response.to.have.status(200);",
-									"});",
-									"",
-									"pm.test(\"Get client with response types\", function () {",
-									"    pm.response.to.be.header('Content-Type', 'application/json');",
-									"    var body = pm.response.json();",
-									"    pm.expect(body.client_name).to.eql('Client name updated via DCR');",
-									"    pm.expect(body).to.have.property(\"response_types\");",
-									"    pm.expect(body.response_types).to.eql(['code']);",
-									"});",
-									"",
-									"pm.test(\"One time Token\", function() {",
-									"    var body = pm.response.json();",
-									"    pm.expect(body).to.have.property('registration_access_token');",
-									"    pm.expect(body.registration_access_token).to.not.eql(pm.environment.get('registrationAccessToken'));",
-									"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
-									"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
-									"});"
-								],
-								"type": "text/javascript"
-							}
-						}
-					],
-					"request": {
-						"method": "PUT",
-						"header": [
-							{
-								"key": "Content-Type",
-								"type": "text",
-								"value": "application/json"
-							},
-							{
-								"key": "Authorization",
-								"type": "text",
-								"value": "Bearer {{registrationAccessToken}}"
-							}
-						],
-						"body": {
-							"mode": "raw",
-							"raw": "{\n    \"redirect_uris\": [\n        \"https://client.example.org/callback\",\n        \"https://client.example.org/callback2\"\n    ],\n    \"response_types\": [\n        \"code\"\n    ],\n    \"grant_types\": [\n        \"authorization_code\"\n    ],\n    \"application_type\": \"web\",\n    \"contacts\": [\n        \"marie@example.org\",\n        \"jeanne@example.org\"\n    ],\n\t\"client_name\": \"Client name updated via DCR\",\n    \"logo_uri\": \"https://client.example.org/logo.png\",\n    \"subject_type\": \"public\",\n    \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\",\n    \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n    \"token_endpoint_auth_method\": \"client_secret_basic\",\n    \"require_auth_time\": false,\n    \"request_uris\": [\n        \"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"\n    ],\n    \"scope\": \"openid\"\n}"
-						},
-						"url": {
-							"raw": "{{registrationClientUri}}",
-							"host": [
-								"{{registrationClientUri}}"
-							]
-						}
-					},
-					"response": []
-				},
-				{
-					"name": "Delete client - with registration token",
-					"event": [
-						{
-							"listen": "test",
-							"script": {
-								"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
-								"exec": [
-									"pm.test(\"Status code is 204\", function () {",
-									"    pm.response.to.have.status(204);",
-									"});",
-									""
-								],
-								"type": "text/javascript"
-							}
-						}
-					],
-					"request": {
-						"method": "DELETE",
-						"header": [
-							{
-								"key": "Content-Type",
-								"type": "text",
-								"value": "application/json"
-							},
-							{
-								"key": "Authorization",
-								"type": "text",
-								"value": "Bearer {{registrationAccessToken}}"
-							}
-						],
-						"body": {
-							"mode": "raw",
-							"raw": ""
-						},
-						"url": {
-							"raw": "{{registrationClientUri}}",
-							"host": [
-								"{{registrationClientUri}}"
-							]
-						}
-					},
-					"response": []
-				}
-			]
-		},
+		{
+			"name": "Case - Nominal",
+			"item": [
+				{
+					"name": "web application",
+					"item": [
+						{
+							"name": "Register client - web application",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 201\", function () {",
+											"    pm.response.to.have.status(201);",
+											"});",
+											"",
+											"pm.test(\"Has default attributes\", function () {",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property('application_type');",
+											"    pm.expect(body).to.have.property('response_types');",
+											"    pm.expect(body).to.have.property('grant_types');",
+											"    pm.expect(body).to.have.property('client_name');",
+											"    pm.expect(body).to.have.property('client_id');",
+											"    pm.expect(body).to.have.property('client_secret');",
+											"    pm.expect(body.application_type).to.eql('web');",
+											"    pm.expect(body.response_types).to.eql(['code']);",
+											"    pm.expect(body.grant_types).to.eql(['authorization_code']);",
+											"    pm.expect(body.client_name).to.eql('Unknown Client');",
+											"    ",
+											"    pm.environment.set('newClientForDCRTests', body.id);",
+											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
+											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n   \"redirect_uris\":\n     [\"https://client.example.org/callback\",\n      \"https://client.example.org/callback2\"],\n   \"logo_uri\": \"https://client.example.org/logo.png\",\n   \"subject_type\": \"public\",\n   \"token_endpoint_auth_method\": \"client_secret_basic\",\n   \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\",\n   \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n   \"contacts\": [\"ve7jtb@example.org\", \"mary@example.org\"],\n   \"request_uris\":\n     [\"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"]\n  }"
+								},
+								"url": {
+									"raw": "{{registrationEndpoint}}",
+									"host": [
+										"{{registrationEndpoint}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Get client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"Get client with response types\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property(\"redirect_uris\");",
+											"    pm.expect(body).to.have.property(\"grant_types\");",
+											"    pm.expect(body.response_types).to.eql([ 'code' ]);",
+											"    pm.expect(body.grant_types).to.eql([ 'authorization_code' ]);",
+											"    pm.expect(body.client_name).to.eql('Unknown Client');",
+											"    ",
+											"    //The Authorization Server need not include the registration_access_token or registration_client_uri value in this response unless they have been updated.",
+											"    pm.expect(body).to.not.have.property('registration_access_token');",
+											"    pm.expect(body).to.not.have.property('registration_client_uri');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": ""
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Patch client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"Get client with response types\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.client_name).to.eql('Client patched via DCR');",
+											"    pm.expect(body).to.have.property(\"response_types\");",
+											"    pm.expect(body.response_types).to.eql(['token', 'code', 'code id_token']);",
+											"    pm.expect(body.grant_types).to.eql([ 'implicit','authorization_code' ]);",
+											"});",
+											"",
+											"pm.test(\"One time Token\", function() {",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property('registration_access_token');",
+											"    pm.expect(body.registration_access_token).to.not.eql(pm.environment.get('registrationAccessToken'));",
+											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
+											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PATCH",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n   \"client_name\": \"Client patched via DCR\",\n   \"response_types\" : [\"token\", \"code\", \"code id_token\"]\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Update client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"Get client with response types\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.client_name).to.eql('Client name updated via DCR');",
+											"    pm.expect(body).to.have.property(\"response_types\");",
+											"    pm.expect(body.response_types).to.eql(['code']);",
+											"});",
+											"",
+											"pm.test(\"One time Token\", function() {",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property('registration_access_token');",
+											"    pm.expect(body.registration_access_token).to.not.eql(pm.environment.get('registrationAccessToken'));",
+											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
+											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n    \"redirect_uris\": [\n        \"https://client.example.org/callback\",\n        \"https://client.example.org/callback2\"\n    ],\n    \"response_types\": [\n        \"code\"\n    ],\n    \"grant_types\": [\n        \"authorization_code\"\n    ],\n    \"application_type\": \"web\",\n    \"contacts\": [\n        \"marie@example.org\",\n        \"jeanne@example.org\"\n    ],\n\t\"client_name\": \"Client name updated via DCR\",\n    \"logo_uri\": \"https://client.example.org/logo.png\",\n    \"subject_type\": \"public\",\n    \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\",\n    \"userinfo_encrypted_response_enc\": \"A128CBC-HS256\",\n    \"token_endpoint_auth_method\": \"client_secret_basic\",\n    \"require_auth_time\": false,\n    \"request_uris\": [\n        \"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"\n    ],\n    \"scope\": \"openid\"\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Delete client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 204\", function () {",
+											"    pm.response.to.have.status(204);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "DELETE",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": ""
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						}
+					],
+					"_postman_isSubFolder": true
+				},
+				{
+					"name": "client application",
+					"item": [
+						{
+							"name": "Register client - client application",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 201\", function () {",
+											"    pm.response.to.have.status(201);",
+											"});",
+											"",
+											"pm.test(\"Has default attributes\", function () {",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property('application_type');",
+											"    pm.expect(body).to.have.property('response_types');",
+											"    pm.expect(body).to.have.property('grant_types');",
+											"    pm.expect(body).to.have.property('client_name');",
+											"    pm.expect(body).to.have.property('client_id');",
+											"    pm.expect(body).to.have.property('client_secret');",
+											"    pm.expect(body.response_types).to.eql([]);",
+											"    pm.expect(body.application_type).to.eql('server');",
+											"    pm.expect(body.grant_types).to.eql(['client_credentials']);",
+											"    pm.expect(body.client_name).to.eql('Unknown Client');",
+											"    ",
+											"    pm.environment.set('newClientForDCRTests', body.id);",
+											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
+											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{access_token}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n\t\"application_type\": \"server\",\n\t\"redirect_uris\": null,\n\t\"grant_types\": [\"client_credentials\"],\n\t\"response_types\": null\n}"
+								},
+								"url": {
+									"raw": "{{registrationEndpoint}}",
+									"host": [
+										"{{registrationEndpoint}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Get client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"Get client with response types\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property(\"grant_types\");",
+											"    pm.expect(body.response_types).to.eql([]);",
+											"    pm.expect(body.grant_types).to.eql([ 'client_credentials' ]);",
+											"    ",
+											"    //The Authorization Server need not include the registration_access_token or registration_client_uri value in this response unless they have been updated.",
+											"    pm.expect(body).to.not.have.property('registration_access_token');",
+											"    pm.expect(body).to.not.have.property('registration_client_uri');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": ""
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Patch client - invalidRedirectUri",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 400\", function () {",
+											"    pm.response.to.have.status(400);",
+											"});",
+											"",
+											"pm.test(\"Redirect uris are missing\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.error).to.eql('invalid_redirect_uri');",
+											"    pm.expect(body.error_description).to.eql('Missing or invalid redirect_uris.');",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PATCH",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n   \"client_name\": \"Adding code or token response type means a redirect_uri will be required.\",\n   \"response_types\" : [\"token\", \"code\", \"code id_token\"]\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Patch client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"Get client with response types\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property(\"response_types\");",
+											"    pm.expect(body.response_types).to.eql(['token', 'code', 'code id_token']);",
+											"    pm.expect(body).to.have.property(\"grant_types\");",
+											"    pm.expect(body.grant_types).to.eql(['implicit', 'client_credentials', 'authorization_code']);",
+											"});",
+											"",
+											"pm.test(\"One time Token\", function() {",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property('registration_access_token');",
+											"    pm.expect(body.registration_access_token).to.not.eql(pm.environment.get('registrationAccessToken'));",
+											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
+											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PATCH",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n   \"client_name\": \"Do not block even if we add code/implicit in addition to client_credentials\",\n   \"response_types\" : [\"token\", \"code\", \"code id_token\"],\n   \"redirect_uris\": [\"https://callback\"]\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Update client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 200\", function () {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"Get client with response types\", function () {",
+											"    pm.response.to.be.header('Content-Type', 'application/json');",
+											"    var body = pm.response.json();",
+											"    pm.expect(body.client_name).to.eql('Client name updated via DCR');",
+											"    pm.expect(body).to.have.property(\"response_types\");",
+											"    pm.expect(body.response_types).to.eql([]);",
+											"    pm.expect(body).to.have.property(\"grant_types\");",
+											"    pm.expect(body.grant_types).to.eql([\"client_credentials\"]);",
+											"});",
+											"",
+											"pm.test(\"One time Token\", function() {",
+											"    var body = pm.response.json();",
+											"    pm.expect(body).to.have.property('registration_access_token');",
+											"    pm.expect(body.registration_access_token).to.not.eql(pm.environment.get('registrationAccessToken'));",
+											"    pm.environment.set('registrationAccessToken', body.registration_access_token);",
+											"    pm.environment.set('registrationClientUri', body.registration_client_uri);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n\t\"application_type\": \"server\",\n\t\"redirect_uris\": null,\n\t\"grant_types\": [\"client_credentials\"],\n\t\"response_types\": null,\n\t\n    \"contacts\": [\n        \"marie@example.org\",\n        \"jeanne@example.org\"\n    ],\n\t\"client_name\": \"Client name updated via DCR\",\n    \"logo_uri\": \"https://client.example.org/logo.png\",\n    \"subject_type\": \"public\",\n    \"token_endpoint_auth_method\": \"client_secret_basic\",\n    \"require_auth_time\": false,\n    \"request_uris\": [\n        \"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA\"\n    ]\n}"
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Delete client - with registration token",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"id": "d83b2401-3844-4147-bbb3-abe08b43a342",
+										"exec": [
+											"pm.test(\"Status code is 204\", function () {",
+											"    pm.response.to.have.status(204);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "DELETE",
+								"header": [
+									{
+										"key": "Content-Type",
+										"type": "text",
+										"value": "application/json"
+									},
+									{
+										"key": "Authorization",
+										"type": "text",
+										"value": "Bearer {{registrationAccessToken}}"
+									}
+								],
+								"body": {
+									"mode": "raw",
+									"raw": ""
+								},
+								"url": {
+									"raw": "{{registrationClientUri}}",
+									"host": [
+										"{{registrationClientUri}}"
+									]
+								}
+							},
+							"response": []
+						}
+					],
+					"_postman_isSubFolder": true
+				}
+			]
+		},
 		{
 			"name": "Case - Signing id_token",
 			"item": [
 				{
-					"name": "Generate token - client",
+					"name": "Generate token - Case signing id_token",
 					"event": [
 						{
 							"listen": "test",
@@ -3519,7 +4222,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "{\n\t\"client_name\":\"client_rs256\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"response_types\": [\"code\",\"token\",\"id_token\"],\n    \"token_endpoint_auth_method\": \"client_secret_basic\",\n    \"id_token_signed_response_alg\": \"RS256\"\n}"
+							"raw": "{\n\t\"client_name\":\"client_rs256\",\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"response_types\": [\"code\",\"token\",\"id_token\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"scope\": \"openid\",\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"token_endpoint_auth_method\": \"client_secret_basic\",\n    \"id_token_signed_response_alg\": \"RS256\"\n}"
 						},
 						"url": {
 							"raw": "{{registrationEndpoint}}",
@@ -3602,7 +4305,8 @@
 								{
 									"key": "scope",
 									"value": "openid",
-									"type": "text"
+									"type": "text",
+									"disabled": true
 								}
 							]
 						},
@@ -3922,7 +4626,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"response_types\": [\"code\",\"id_token\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"id_token_encrypted_response_alg\": \"RSA-OAEP-256\"\n}"
+									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"scope\": \"openid\",\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"response_types\": [\"code\",\"id_token\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"id_token_encrypted_response_alg\": \"RSA-OAEP-256\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -4101,7 +4805,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"response_types\": [\"code\",\"id_token\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"jwks\": {\n        \"keys\": [\n\t\t\t{  \n\t\t\t\t\"kty\": \"RSA\",\n\t\t\t\t\"use\": \"enc\",\n\t\t\t\t\"kid\": \"rsa-encryption-256\",\n\t\t\t\t\"e\": \"AQAB\",\n\t\t\t\t\"n\": \"lFAsvOm58TV5q9zyb3psQSESezZtYLZryGjq8LMnuqRt9cdPQCvMrnjcqdFWiXkD4ZXRO2Wp1iyzgprecx3dAnaD-KHlZR7vsFEmDh27DgNvEx5jKRSy5N2quI2LJw66Jb9JeMqoX6vtv_z3PRHb-zUhnIw6tBwZtuNE-AZSC6atr8ZCLXn6RPqJq_eoGgG-xaAzWPyRXDIqWPVO0RD3odjs6er7BcqVyHg54DyylrmRI4m6xERxpuNYI57bQN5_7a_3tR7hLeHJ8J1mNraMLH7H5_aAM_oSqKBEG9jHSTR7JsI3gSvsNOG-nP9jYxw7fH_c1XfRuTEJfBPEZxzD2Q\"\n\t\t\t},\n            {\n                \"kty\": \"RSA\",\n                \"use\": \"sig\",\n                \"kid\": \"rsa-signature\",\n                \"e\": \"AQAB\",\n                \"n\": \"pRXXMvbZC4-I8nmeirMmr_wlo-lpZo2cyfXLPSduieEsfLeO38vIFdXbVTQ-OAeihFrvbxHELt2mNwCH3gbosd0P-pyYtUOaGmi7rLW9Wik8JcNCKA-v7q2JWmBeRFyRAuwf343gnxNL1mpUHfhqd4eswRiO55iwFT8a8gmxSOm8VXjg2aeUjkI3diT84rGR-wK77OcXeF2zJzjRDe0yFla0Tjb1RNTNkVQBJAQ3VQOOaNL7bXajR79ERlMKCjRFIZ0QCB7Nf6LtMwp9QWRdFrm7RXIPpN1V03E4v51gq82URjuQvEANe-VGRVSBij_GcOSLGjyZQi-yGVyPjNVl1Q\"\n            },\n            {\n                \"kty\": \"EC\",\n                \"use\": \"sig\",\n                \"crv\": \"P-256\",\n                \"kid\": \"elliptic-curve-signature\",\n                \"x\": \"R4JmPwezbzLuyGkonWIkezzplUfed5b6F5PL4j0zdf8\",\n                \"y\": \"QQRGKwRV9jHSlHjUhOQ0FqdQEddFBPCHZXpoFjvGmcY\"\n            },\n\t\t\t{  \n\t\t\t\t\"kty\":\"EC\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"crv\":\"P-521\",\n                \"kid\": \"elliptic-curve-encryption\",\n\t\t\t\t\"x\":\"AfEFyeYAr1TwmvCxvqgWPEg4Vvf50RC2OdkYfTS30dInZwX-Ebn6elp4fQ0GOdOBbYRq9b2gQ79Cd1AytQhdF6To\",\n\t\t\t\t\"y\":\"Abj0w4nSumQWtO6AV7ufQN6VpmJoKlWmz9KB6BUU0ANcj4aTJjBE9WNiGCqFpvaIdEWZWcSsZNYGKT3rJ71AfLdm\"\n\t\t\t},\n\t\t\t{  \n\t\t\t\t\"kty\":\"OKP\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"kid\":\"edwards-curve-encryption\",\n\t\t\t\t\"crv\":\"X25519\",\n\t\t\t\t\"x\":\"vBNW8f19leF79U4U6NrDDQaK_i5kL0iMKghB39AUT2I\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"128bits\",\n\t\t\t\t\"k\" : \"p94TA_PhiVUdi_yxPbviAw\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"192bits\",\n\t\t\t\t\"k\" : \"G9jUYv3b0-0wZWCGxAnIUH6gI0kjeXj4\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"256bits\",\n\t\t\t\t\"k\" : \"pzx01XDfexcfxHWtk_MzjfCin5NMy3KBx2xtjrX1G-E\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"384bits\",\n\t\t\t\t\"k\" : \"MBNrGN8nwS7hlOVfqEy6qA98bzyo1BLGxr-kyN1E4UXYWQDkBg4L7AQRwpZdrKKS\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"512bits\",\n\t\t\t\t\"k\" : \"LfWisS5p-ohMbNbeWdiSapnHgA62XPu8DXzyzNZQHtQPglHf0Lb6NUM-8aQGj_YWErvODY5rQkpKeolrBKkcmg\"\n\t\t\t}\n        ]\n    }\n}"
+									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"scope\": \"openid\",\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"response_types\": [\"code\",\"id_token\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"jwks\": {\n        \"keys\": [\n\t\t\t{  \n\t\t\t\t\"kty\": \"RSA\",\n\t\t\t\t\"use\": \"enc\",\n\t\t\t\t\"kid\": \"rsa-encryption-256\",\n\t\t\t\t\"e\": \"AQAB\",\n\t\t\t\t\"n\": \"lFAsvOm58TV5q9zyb3psQSESezZtYLZryGjq8LMnuqRt9cdPQCvMrnjcqdFWiXkD4ZXRO2Wp1iyzgprecx3dAnaD-KHlZR7vsFEmDh27DgNvEx5jKRSy5N2quI2LJw66Jb9JeMqoX6vtv_z3PRHb-zUhnIw6tBwZtuNE-AZSC6atr8ZCLXn6RPqJq_eoGgG-xaAzWPyRXDIqWPVO0RD3odjs6er7BcqVyHg54DyylrmRI4m6xERxpuNYI57bQN5_7a_3tR7hLeHJ8J1mNraMLH7H5_aAM_oSqKBEG9jHSTR7JsI3gSvsNOG-nP9jYxw7fH_c1XfRuTEJfBPEZxzD2Q\"\n\t\t\t},\n            {\n                \"kty\": \"RSA\",\n                \"use\": \"sig\",\n                \"kid\": \"rsa-signature\",\n                \"e\": \"AQAB\",\n                \"n\": \"pRXXMvbZC4-I8nmeirMmr_wlo-lpZo2cyfXLPSduieEsfLeO38vIFdXbVTQ-OAeihFrvbxHELt2mNwCH3gbosd0P-pyYtUOaGmi7rLW9Wik8JcNCKA-v7q2JWmBeRFyRAuwf343gnxNL1mpUHfhqd4eswRiO55iwFT8a8gmxSOm8VXjg2aeUjkI3diT84rGR-wK77OcXeF2zJzjRDe0yFla0Tjb1RNTNkVQBJAQ3VQOOaNL7bXajR79ERlMKCjRFIZ0QCB7Nf6LtMwp9QWRdFrm7RXIPpN1V03E4v51gq82URjuQvEANe-VGRVSBij_GcOSLGjyZQi-yGVyPjNVl1Q\"\n            },\n            {\n                \"kty\": \"EC\",\n                \"use\": \"sig\",\n                \"crv\": \"P-256\",\n                \"kid\": \"elliptic-curve-signature\",\n                \"x\": \"R4JmPwezbzLuyGkonWIkezzplUfed5b6F5PL4j0zdf8\",\n                \"y\": \"QQRGKwRV9jHSlHjUhOQ0FqdQEddFBPCHZXpoFjvGmcY\"\n            },\n\t\t\t{  \n\t\t\t\t\"kty\":\"EC\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"crv\":\"P-521\",\n                \"kid\": \"elliptic-curve-encryption\",\n\t\t\t\t\"x\":\"AfEFyeYAr1TwmvCxvqgWPEg4Vvf50RC2OdkYfTS30dInZwX-Ebn6elp4fQ0GOdOBbYRq9b2gQ79Cd1AytQhdF6To\",\n\t\t\t\t\"y\":\"Abj0w4nSumQWtO6AV7ufQN6VpmJoKlWmz9KB6BUU0ANcj4aTJjBE9WNiGCqFpvaIdEWZWcSsZNYGKT3rJ71AfLdm\"\n\t\t\t},\n\t\t\t{  \n\t\t\t\t\"kty\":\"OKP\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"kid\":\"edwards-curve-encryption\",\n\t\t\t\t\"crv\":\"X25519\",\n\t\t\t\t\"x\":\"vBNW8f19leF79U4U6NrDDQaK_i5kL0iMKghB39AUT2I\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"128bits\",\n\t\t\t\t\"k\" : \"p94TA_PhiVUdi_yxPbviAw\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"192bits\",\n\t\t\t\t\"k\" : \"G9jUYv3b0-0wZWCGxAnIUH6gI0kjeXj4\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"256bits\",\n\t\t\t\t\"k\" : \"pzx01XDfexcfxHWtk_MzjfCin5NMy3KBx2xtjrX1G-E\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"384bits\",\n\t\t\t\t\"k\" : \"MBNrGN8nwS7hlOVfqEy6qA98bzyo1BLGxr-kyN1E4UXYWQDkBg4L7AQRwpZdrKKS\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"512bits\",\n\t\t\t\t\"k\" : \"LfWisS5p-ohMbNbeWdiSapnHgA62XPu8DXzyzNZQHtQPglHf0Lb6NUM-8aQGj_YWErvODY5rQkpKeolrBKkcmg\"\n\t\t\t}\n        ]\n    }\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -21089,7 +21793,7 @@
 						],
 						"body": {
 							"mode": "raw",
-							"raw": "{\n\t\"client_name\":\"client_rs384\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"response_types\": [\"code\",\"token\"],\n    \"token_endpoint_auth_method\": \"client_secret_basic\",\n    \"userinfo_signed_response_alg\": \"RS384\"\n}"
+							"raw": "{\n\t\"client_name\":\"client_rs384\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"authorization_code\",\"implicit\",\"password\"],\n    \"scope\": \"openid\",\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"response_types\": [\"code\",\"token\"],\n    \"token_endpoint_auth_method\": \"client_secret_basic\",\n    \"userinfo_signed_response_alg\": \"RS384\"\n}"
 						},
 						"url": {
 							"raw": "{{registrationEndpoint}}",
@@ -21233,6 +21937,10 @@
 								"value": "Bearer {{access_token}}"
 							}
 						],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
 						"url": {
 							"raw": "{{userinfoEndpoint}}",
 							"host": [
@@ -21451,6 +22159,10 @@
 								"value": "Bearer {{access_token}}"
 							}
 						],
+						"body": {
+							"mode": "raw",
+							"raw": ""
+						},
 						"url": {
 							"raw": "{{userinfoEndpoint}}",
 							"host": [
@@ -21717,7 +22429,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"password\"],\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\"\n}"
+									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"password\"],\n    \"scope\": \"openid\",\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"userinfo_encrypted_response_alg\": \"RSA-OAEP-256\"\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -22056,7 +22768,7 @@
 								],
 								"body": {
 									"mode": "raw",
-									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"password\"],\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"jwks\": {\n        \"keys\": [\n\t\t\t{  \n\t\t\t\t\"kty\": \"RSA\",\n\t\t\t\t\"use\": \"enc\",\n\t\t\t\t\"kid\": \"rsa-encryption-256\",\n\t\t\t\t\"e\": \"AQAB\",\n\t\t\t\t\"n\": \"lFAsvOm58TV5q9zyb3psQSESezZtYLZryGjq8LMnuqRt9cdPQCvMrnjcqdFWiXkD4ZXRO2Wp1iyzgprecx3dAnaD-KHlZR7vsFEmDh27DgNvEx5jKRSy5N2quI2LJw66Jb9JeMqoX6vtv_z3PRHb-zUhnIw6tBwZtuNE-AZSC6atr8ZCLXn6RPqJq_eoGgG-xaAzWPyRXDIqWPVO0RD3odjs6er7BcqVyHg54DyylrmRI4m6xERxpuNYI57bQN5_7a_3tR7hLeHJ8J1mNraMLH7H5_aAM_oSqKBEG9jHSTR7JsI3gSvsNOG-nP9jYxw7fH_c1XfRuTEJfBPEZxzD2Q\"\n\t\t\t},\n            {\n                \"kty\": \"RSA\",\n                \"use\": \"sig\",\n                \"kid\": \"rsa-signature\",\n                \"e\": \"AQAB\",\n                \"n\": \"pRXXMvbZC4-I8nmeirMmr_wlo-lpZo2cyfXLPSduieEsfLeO38vIFdXbVTQ-OAeihFrvbxHELt2mNwCH3gbosd0P-pyYtUOaGmi7rLW9Wik8JcNCKA-v7q2JWmBeRFyRAuwf343gnxNL1mpUHfhqd4eswRiO55iwFT8a8gmxSOm8VXjg2aeUjkI3diT84rGR-wK77OcXeF2zJzjRDe0yFla0Tjb1RNTNkVQBJAQ3VQOOaNL7bXajR79ERlMKCjRFIZ0QCB7Nf6LtMwp9QWRdFrm7RXIPpN1V03E4v51gq82URjuQvEANe-VGRVSBij_GcOSLGjyZQi-yGVyPjNVl1Q\"\n            },\n            {\n                \"kty\": \"EC\",\n                \"use\": \"sig\",\n                \"crv\": \"P-256\",\n                \"kid\": \"elliptic-curve-signature\",\n                \"x\": \"R4JmPwezbzLuyGkonWIkezzplUfed5b6F5PL4j0zdf8\",\n                \"y\": \"QQRGKwRV9jHSlHjUhOQ0FqdQEddFBPCHZXpoFjvGmcY\"\n            },\n\t\t\t{  \n\t\t\t\t\"kty\":\"EC\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"crv\":\"P-521\",\n                \"kid\": \"elliptic-curve-encryption\",\n\t\t\t\t\"x\":\"AfEFyeYAr1TwmvCxvqgWPEg4Vvf50RC2OdkYfTS30dInZwX-Ebn6elp4fQ0GOdOBbYRq9b2gQ79Cd1AytQhdF6To\",\n\t\t\t\t\"y\":\"Abj0w4nSumQWtO6AV7ufQN6VpmJoKlWmz9KB6BUU0ANcj4aTJjBE9WNiGCqFpvaIdEWZWcSsZNYGKT3rJ71AfLdm\"\n\t\t\t},\n\t\t\t{  \n\t\t\t\t\"kty\":\"OKP\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"kid\":\"edwards-curve-encryption\",\n\t\t\t\t\"crv\":\"X25519\",\n\t\t\t\t\"x\":\"vBNW8f19leF79U4U6NrDDQaK_i5kL0iMKghB39AUT2I\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"128bits\",\n\t\t\t\t\"k\" : \"p94TA_PhiVUdi_yxPbviAw\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"192bits\",\n\t\t\t\t\"k\" : \"G9jUYv3b0-0wZWCGxAnIUH6gI0kjeXj4\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"256bits\",\n\t\t\t\t\"k\" : \"pzx01XDfexcfxHWtk_MzjfCin5NMy3KBx2xtjrX1G-E\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"384bits\",\n\t\t\t\t\"k\" : \"MBNrGN8nwS7hlOVfqEy6qA98bzyo1BLGxr-kyN1E4UXYWQDkBg4L7AQRwpZdrKKS\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"512bits\",\n\t\t\t\t\"k\" : \"LfWisS5p-ohMbNbeWdiSapnHgA62XPu8DXzyzNZQHtQPglHf0Lb6NUM-8aQGj_YWErvODY5rQkpKeolrBKkcmg\"\n\t\t\t}\n        ]\n    }\n}"
+									"raw": "{\n\t\"client_name\": \"Client test for JWE - no jwks\",\n    \"application_type\": \"web\",\n    \"contacts\": [\"roland@example.com\"],\n    \"grant_types\": [\"password\"],\n    \"scope\": \"openid\",\n    \"post_logout_redirect_uris\": [\"https://op-test:60001/logout\"],\n    \"redirect_uris\": [\"https://op-test:60001/authz_cb\"],\n    \"request_uris\": [\"https://op-test:60001/requests/4472f1ee2cd34273a9b8bff4be1549418e5dd1b182639b7b2ae21d93e387467e#hNN9dc7MUCrZF0Jq\"],\n    \"token_endpoint_auth_method\": \"private_key_jwt\",\n    \"jwks\": {\n        \"keys\": [\n\t\t\t{  \n\t\t\t\t\"kty\": \"RSA\",\n\t\t\t\t\"use\": \"enc\",\n\t\t\t\t\"kid\": \"rsa-encryption-256\",\n\t\t\t\t\"e\": \"AQAB\",\n\t\t\t\t\"n\": \"lFAsvOm58TV5q9zyb3psQSESezZtYLZryGjq8LMnuqRt9cdPQCvMrnjcqdFWiXkD4ZXRO2Wp1iyzgprecx3dAnaD-KHlZR7vsFEmDh27DgNvEx5jKRSy5N2quI2LJw66Jb9JeMqoX6vtv_z3PRHb-zUhnIw6tBwZtuNE-AZSC6atr8ZCLXn6RPqJq_eoGgG-xaAzWPyRXDIqWPVO0RD3odjs6er7BcqVyHg54DyylrmRI4m6xERxpuNYI57bQN5_7a_3tR7hLeHJ8J1mNraMLH7H5_aAM_oSqKBEG9jHSTR7JsI3gSvsNOG-nP9jYxw7fH_c1XfRuTEJfBPEZxzD2Q\"\n\t\t\t},\n            {\n                \"kty\": \"RSA\",\n                \"use\": \"sig\",\n                \"kid\": \"rsa-signature\",\n                \"e\": \"AQAB\",\n                \"n\": \"pRXXMvbZC4-I8nmeirMmr_wlo-lpZo2cyfXLPSduieEsfLeO38vIFdXbVTQ-OAeihFrvbxHELt2mNwCH3gbosd0P-pyYtUOaGmi7rLW9Wik8JcNCKA-v7q2JWmBeRFyRAuwf343gnxNL1mpUHfhqd4eswRiO55iwFT8a8gmxSOm8VXjg2aeUjkI3diT84rGR-wK77OcXeF2zJzjRDe0yFla0Tjb1RNTNkVQBJAQ3VQOOaNL7bXajR79ERlMKCjRFIZ0QCB7Nf6LtMwp9QWRdFrm7RXIPpN1V03E4v51gq82URjuQvEANe-VGRVSBij_GcOSLGjyZQi-yGVyPjNVl1Q\"\n            },\n            {\n                \"kty\": \"EC\",\n                \"use\": \"sig\",\n                \"crv\": \"P-256\",\n                \"kid\": \"elliptic-curve-signature\",\n                \"x\": \"R4JmPwezbzLuyGkonWIkezzplUfed5b6F5PL4j0zdf8\",\n                \"y\": \"QQRGKwRV9jHSlHjUhOQ0FqdQEddFBPCHZXpoFjvGmcY\"\n            },\n\t\t\t{  \n\t\t\t\t\"kty\":\"EC\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"crv\":\"P-521\",\n                \"kid\": \"elliptic-curve-encryption\",\n\t\t\t\t\"x\":\"AfEFyeYAr1TwmvCxvqgWPEg4Vvf50RC2OdkYfTS30dInZwX-Ebn6elp4fQ0GOdOBbYRq9b2gQ79Cd1AytQhdF6To\",\n\t\t\t\t\"y\":\"Abj0w4nSumQWtO6AV7ufQN6VpmJoKlWmz9KB6BUU0ANcj4aTJjBE9WNiGCqFpvaIdEWZWcSsZNYGKT3rJ71AfLdm\"\n\t\t\t},\n\t\t\t{  \n\t\t\t\t\"kty\":\"OKP\",\n\t\t\t\t\"use\":\"enc\",\n\t\t\t\t\"kid\":\"edwards-curve-encryption\",\n\t\t\t\t\"crv\":\"X25519\",\n\t\t\t\t\"x\":\"vBNW8f19leF79U4U6NrDDQaK_i5kL0iMKghB39AUT2I\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"128bits\",\n\t\t\t\t\"k\" : \"p94TA_PhiVUdi_yxPbviAw\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"192bits\",\n\t\t\t\t\"k\" : \"G9jUYv3b0-0wZWCGxAnIUH6gI0kjeXj4\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"256bits\",\n\t\t\t\t\"k\" : \"pzx01XDfexcfxHWtk_MzjfCin5NMy3KBx2xtjrX1G-E\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"384bits\",\n\t\t\t\t\"k\" : \"MBNrGN8nwS7hlOVfqEy6qA98bzyo1BLGxr-kyN1E4UXYWQDkBg4L7AQRwpZdrKKS\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"kty\": \"oct\",\n\t\t\t\t\"kid\": \"512bits\",\n\t\t\t\t\"k\" : \"LfWisS5p-ohMbNbeWdiSapnHgA62XPu8DXzyzNZQHtQPglHf0Lb6NUM-8aQGj_YWErvODY5rQkpKeolrBKkcmg\"\n\t\t\t}\n        ]\n    }\n}"
 								},
 								"url": {
 									"raw": "{{registrationEndpoint}}",
@@ -47981,4 +48693,4 @@
 			"response": []
 		}
 	]
-}
\ No newline at end of file
+}
diff --git a/postman/collections/graviteeio-am-openid-discovery-collection.json b/postman/collections/graviteeio-am-openid-discovery-collection.json
index 4523fd78e8..ceb5a14a4d 100644
--- a/postman/collections/graviteeio-am-openid-discovery-collection.json
+++ b/postman/collections/graviteeio-am-openid-discovery-collection.json
@@ -119,62 +119,6 @@
 					},
 					"response": []
 				},
-				{
-					"name": "Create jks certificate rs256",
-					"event": [
-						{
-							"listen": "test",
-							"script": {
-								"id": "a1ab79e9-b254-47f9-8af9-e6ab3e47ab58",
-								"exec": [
-									"pm.test(\"Status code is 201\", function () {",
-									"    pm.response.to.have.status(201);",
-									"});",
-									"",
-									"pm.test(\"Extension Grant - create jks certificate\", function () {",
-									"    var jsonData = pm.response.json();",
-									"    pm.expect(jsonData).to.have.property('id');",
-									"    pm.environment.set('certificateJks', jsonData.id);",
-									"});"
-								],
-								"type": "text/javascript"
-							}
-						}
-					],
-					"request": {
-						"method": "POST",
-						"header": [
-							{
-								"key": "Authorization",
-								"type": "text",
-								"value": "Bearer {{token}}"
-							},
-							{
-								"key": "Content-Type",
-								"name": "Content-Type",
-								"type": "text",
-								"value": "application/json"
-							}
-						],
-						"body": {
-							"mode": "raw",
-							"raw": "{\n  \"type\": \"javakeystore-am-certificate\",\n  \"configuration\": \"{\\\"jks\\\":\\\"{\\\\\\\"name\\\\\\\":\\\\\\\"server.jks\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"\\\\\\\",\\\\\\\"size\\\\\\\":2237,\\\\\\\"content\\\\\\\":\\\\\\\"/u3+7QAAAAIAAAABAAAAAQAJbXl0ZXN0a2V5AAABYkPPuJkAAAUCMIIE/jAOBgorBgEEASoCEQEBBQAEggTqr5aJvYjZG/WQ8gGjoB2IzOwULJfXRbSwn0H9SP6vXE7TkFdVC6e7jOsPwwUVKwiTRCrNLL3G9OYyBvQEJv1NdPGYpqrD+4bzr5oVKQbwuXAs455phdjZ5jFlGjjowHBU7loxm5TJDncBfYoffptiStRSjzuuEWRPaRnUtL1PMidp4XdSOxzknBQ86zLz266y6pksmrSyCGxXiZwvnzq2TRvZOAT5haYA1wJOZwXAE4xk00C9Zr5NBIgyAZ0fsuZfquLhxpEgDg8XFsXAL7O4U9ocETktH4j5JnYWng6A90Ke2l4CUKjPvXTMYQr2ll26BjpE/TGyXRMNqqSzZ6tujn9wji1stGUS840AFye/HfZyQlkZBV/CyyDx/OkP0D9U5xO5jCnurGrMrbskIqcLchyb9xobr/RbnrpwMnK2XteCX9WRog064uYY8r722c81jFM6pL9Ue/Jm6h5fkHKZdJPJtMqdZf9fgb8VbxranRQDd3EIxx0yIXBddv6lqWMISXJCAni3MpBwiUAgzDdVVQYJlzu8t1x8cEpIrqD0sNQhGKmmDWwAE2mKJrYLaqaICKG9YaWy65ZPUOdQMUFzYOxpjNAvbDE/ZUs2jU1AbBpCk0HpgoBYckx0bIAN0buwaPUMwBgCzOjaQ6EQkNiORJoBdxqgI2GsN4j3TzUFSUIRZlFRxbn/f1Oo9SSznIfSzMRDEfoZYdLzwm01yBl5VwmCY5azrPGtAl+hmgBOdYM4O+svGTam+E4Iw2abX9T+B1im8ip4fEtn98Pgr//d+1cbYC2kcPMadfjMbp3d62z4DH9ABqTnEHBbfo1GgOpzpMRaKfrKvPap3PniP0YYqwDRJ4zn7OfYmrxVy8MENqGLveIksyvRj1K8Y3uexxZQ6CMAWbUuONJHHfBoTYsK+LdYxl7fCSuxqx9z0V3x5R3PCXchxNqR9f2tU1uDBqlXDESko0g9X0Qi1pLMk8A7wE5g8mChFhhrakrRMauwH0JkyLw+vcVpLqsyxsAcIm5bX3IWivPrbLZRW3lSLofdXj0XEuP2vnxdC82UPI3VQqqAI1UzL9sUl/cqhNGNztyRYAEv3FWttW2YTA1dlgq4DjPIRFAS4HyzgHeg8Jcgg/kRHbaLT4j2JVdqFG22CL+bayA6KqWeHos2bAA3ydw34y3QtJ0cqcH3iUZ0R0z++rG6iwDKPMkNW4osWP51UcFLXY/uNGSoverCQGJsD+wKvyi9KGDCsdjacgZJJtAsyOCxQssIPeB3GWt0rJi86SUqg0praNBXHKcbx5wSvp9i6uuaZhPzcvECPW/kgzPRaZLfneEZI+UPy31/jP8EUfQ9JT2hQ7w69jgVDE0WFhmNt8I/VrCMxFwCqYvA4m8xLmplZhCy+HUbLJMcwAx0yzbvH63kwcOASJC5JrnK0/P7UOc2NdAgXO/WrCZssRresxRNKaZvJTJtTrhElJKP9yD1zjiS4L5/PpGIW5md/qKX91zz0k5AzCqHdhBaRx7K7QVeWVEN8u4ZySbj9vCTLs1jTPcX7YpsPJBRGvqA4j9AYcBLzmhQa1huLVZTANE6j+vkgPvgPq4ToyTMKvUJwLbmIobX0ZyQKPGhe3LVorfM4uaSxq8+jMV4+0uddFNpLm9eJG+ZLbeVlu0157q45lxuQrO1VOvVLdqsrwAAAAEABVguNTA5AAADcTCCA20wggJVoAMCAQICBBCfcKYwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVN0YXRlMQ0wCwYDVQQHEwRDaXR5MRUwEwYDVQQKEwxPcmdhbml6YXRpb24xDTALBgNVBAsTBFVuaXQxEzARBgNVBAMTCldlYiBTZXJ2ZXIwHhcNMTgwMzIwMTQyODI5WhcNMTgwNjE4MTQyODI5WjBnMQswCQYDVQQGEwJVUzEOMAwGA1UECBMFU3RhdGUxDTALBgNVBAcTBENpdHkxFTATBgNVBAoTDE9yZ2FuaXphdGlvbjENMAsGA1UECxMEVW5pdDETMBEGA1UEAxMKV2ViIFNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu+JWbf4oP3xTz33EgXnD0jgL/clO/9lV25GFwygaR8F7qzPaknaR/psyO1acRv3UfrcYdZ2/nnh7PcchjEFmxh11pT3di2KquxsIJBzcYyYUHXbRaBRZ+Oqy884xzPc/IXLfLD5csCI0PQ+XaW/wrp6Mm9/CZNGHLUMjk9Aa9FbPnsh2gLGNkTwf4uvv11z94WFy7oWSzFra26C/zq3I7fywD2/UvYIJCOypAvxOcwdsNXxqEYroBu/jcoyMdXq2AWE6EdzVrZhpgK0QjTIoofa3QreGsdHBR+Cq7hDnGpakGQQVfTlhbzKCtaK9d8PAaOpwzKIcRiVG8NytE/QmECAwEAAaMhMB8wHQYDVR0OBBYEFJTE/I9yfWZ8smIobMkV2dtfpdFhMA0GCSqGSIb3DQEBCwUAA4IBAQCqZhd8O5GUUw1uX6jQKLjqjfzt7dPKMhNSUKPLrBktiJa+ZM/M+mGnEH6/TYcwzazAfeV+JgbY1KpMq1UVOW6KdDga2yXj43mVz7yzVB3KPIdMGSI4pqZxptQ7LEGVtSDsgqpQPi3qpsWUMLMW6heOHKc66Bdf9RE0S1ds+yMg9dNQBkTEXJKR6S+koyDcGnrZgwwVJ5T5+5ZUiGxe2wdGs7DUQCdDVwRZwkWzdIXPnK98PwFh7ivYI6+tnV+AHZg02IDAZ49rwNtQsExeQepNh2IPwCe+7TlfZ8TeiwcxL2ngqKA9LFP2do8YDz9XZbfl9AfS3GXeZsq3ihR3nffqT6271mTSYWrugh9IagHGV2PT6mo=\\\\\\\"}\\\",\\\"storepass\\\":\\\"letmein\\\",\\\"alias\\\":\\\"mytestkey\\\",\\\"keypass\\\":\\\"changeme\\\"}\",\n  \"name\": \"Test\"\n}"
-						},
-						"url": {
-							"raw": "{{management_url}}/management/domains/{{domain}}/certificates",
-							"host": [
-								"{{management_url}}"
-							],
-							"path": [
-								"management",
-								"domains",
-								"{{domain}}",
-								"certificates"
-							]
-						}
-					},
-					"response": []
-				},
 				{
 					"name": "Create jks certificate rs512",
 					"event": [
@@ -462,4 +406,4 @@
 			"response": []
 		}
 	]
-}
\ No newline at end of file
+}


Test patch:
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/jwt/JWTServiceTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/jwt/JWTServiceTest.java
index 7e24b07e1c..e64d13ca5f 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/jwt/JWTServiceTest.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-common/src/test/java/io/gravitee/am/gateway/handler/common/jwt/JWTServiceTest.java
@@ -18,7 +18,6 @@ package io.gravitee.am.gateway.handler.common.jwt;
 import io.gravitee.am.common.jwt.JWT;
 import io.gravitee.am.gateway.handler.common.certificate.CertificateManager;
 import io.gravitee.am.gateway.handler.common.jwt.impl.JWTServiceImpl;
-import io.gravitee.am.gateway.handler.common.vertx.utils.UriBuilderRequest;
 import io.gravitee.am.model.Client;
 import io.reactivex.Maybe;
 import io.reactivex.observers.TestObserver;
@@ -29,11 +28,8 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
-import java.util.Date;
-
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 /**
  * @author Alexandre FARIA (contact at alexandrefaria.net)
diff --git a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/DynamicClientRegistrationServiceTest.java b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/DynamicClientRegistrationServiceTest.java
index 37d1cc0500..5d5334126b 100644
--- a/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/DynamicClientRegistrationServiceTest.java
+++ b/gravitee-am-gateway/gravitee-am-gateway-handler/gravitee-am-gateway-handler-oidc/src/test/java/io/gravitee/am/gateway/handler/oidc/service/clientregistration/DynamicClientRegistrationServiceTest.java
@@ -192,7 +192,6 @@ public class DynamicClientRegistrationServiceTest {
         testObserver.assertNotComplete();
     }
 
-
     @Test
     public void validateClientRegistrationRequest_unknownResponseTypePayload() {
         DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
@@ -205,6 +204,17 @@ public class DynamicClientRegistrationServiceTest {
         testObserver.assertNotComplete();
     }
 
+    @Test
+    public void validateClientRegistrationRequest_ok_emptyResponseTypePayload() {
+        DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
+        request.setRedirectUris(Optional.of(Arrays.asList("https://graviee.io/callback")));
+        request.setResponseTypes(Optional.empty());
+
+        TestObserver testObserver = dcrService.validateClientRegistrationRequest(request).test();
+        testObserver.assertNoErrors();
+        testObserver.assertComplete();
+    }
+
     @Test
     public void validateClientRegistrationRequest_unknownGrantTypePayload() {
         DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
@@ -217,6 +227,18 @@ public class DynamicClientRegistrationServiceTest {
         testObserver.assertNotComplete();
     }
 
+    @Test
+    public void validateClientRegistrationRequest_RefreshTokenGrantTypeOnly() {
+        DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
+        request.setRedirectUris(Optional.of(Arrays.asList("https://graviee.io/callback")));
+        request.setGrantTypes(Optional.of(Arrays.asList("refresh_token")));
+
+        TestObserver testObserver = dcrService.validateClientRegistrationRequest(request).test();
+        testObserver.assertError(InvalidClientMetadataException.class);
+        testObserver.assertError(err -> ((Throwable)err).getMessage().startsWith("refresh_token grant type must be associated with"));
+        testObserver.assertNotComplete();
+    }
+
     @Test
     public void validateClientRegistrationRequest_unsupportedSubjectTypePayload() {
         DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
@@ -499,22 +521,21 @@ public class DynamicClientRegistrationServiceTest {
     }
 
     @Test
-    public void validateClientRegistrationRequest_validateScope_noOpenidScopeRequested() {
+    public void validateClientRegistrationRequest_ok() {
         DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
         request.setRedirectUris(Optional.of(Arrays.asList("https://graviee.io/callback")));
-        request.setScope(Optional.of("scope1 test"));
 
         TestObserver<DynamicClientRegistrationRequest> testObserver = dcrService.validateClientRegistrationRequest(request).test();
         testObserver.assertNoErrors();
         testObserver.assertComplete();
-        testObserver.assertValue(req -> req!=null && req.getScope().get().contains("openid"));
     }
 
     @Test
-    public void validateClientRegistrationRequest_ok() {
+    public void validateClientRegistrationRequest_client_credentials_ok() {
         DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
-        request.setRedirectUris(Optional.of(Arrays.asList("https://graviee.io/callback")));
-
+        request.setRedirectUris(Optional.of(Arrays.asList()));
+        request.setGrantTypes(Optional.of(Arrays.asList("client_credentials")));
+        request.setResponseTypes(Optional.of(Arrays.asList()));
         TestObserver<DynamicClientRegistrationRequest> testObserver = dcrService.validateClientRegistrationRequest(request).test();
         testObserver.assertNoErrors();
         testObserver.assertComplete();
@@ -528,6 +549,15 @@ public class DynamicClientRegistrationServiceTest {
         testObserver.assertNotComplete();
     }
 
+    @Test
+    public void validatePatchRequest_emptyRequest() {
+        DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
+
+        TestObserver<DynamicClientRegistrationRequest> testObserver = dcrService.validateClientPatchRequest(request).test();
+        testObserver.assertNoErrors();
+        testObserver.assertComplete();
+    }
+
     @Test
     public void validatePatchRequest() {
         DynamicClientRegistrationRequest request = new DynamicClientRegistrationRequest();
diff --git a/gravitee-am-service/src/test/java/io/gravitee/am/service/ClientServiceTest.java b/gravitee-am-service/src/test/java/io/gravitee/am/service/ClientServiceTest.java
index 65670642ad..e76d00b0fd 100644
--- a/gravitee-am-service/src/test/java/io/gravitee/am/service/ClientServiceTest.java
+++ b/gravitee-am-service/src/test/java/io/gravitee/am/service/ClientServiceTest.java
@@ -15,11 +15,19 @@
  */
 package io.gravitee.am.service;
 
-import io.gravitee.am.model.*;
+import io.gravitee.am.model.Client;
+import io.gravitee.am.model.Domain;
+import io.gravitee.am.model.Email;
+import io.gravitee.am.model.Form;
+import io.gravitee.am.model.IdentityProvider;
 import io.gravitee.am.model.common.Page;
 import io.gravitee.am.repository.exceptions.TechnicalException;
 import io.gravitee.am.repository.management.api.ClientRepository;
-import io.gravitee.am.service.exception.*;
+import io.gravitee.am.service.exception.ClientAlreadyExistsException;
+import io.gravitee.am.service.exception.ClientNotFoundException;
+import io.gravitee.am.service.exception.InvalidClientMetadataException;
+import io.gravitee.am.service.exception.InvalidRedirectUriException;
+import io.gravitee.am.service.exception.TechnicalManagementException;
 import io.gravitee.am.service.impl.ClientServiceImpl;
 import io.gravitee.am.service.model.NewClient;
 import io.gravitee.am.service.model.PatchClient;
@@ -35,12 +43,18 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.*;
 
 /**
@@ -418,16 +432,30 @@ public class ClientServiceTest {
     }
 
     @Test
-    public void create_generateUuidAsClientId() {
-        Client createClient = Mockito.mock(Client.class);
+    public void create_implicit_invalidRedirectUri() {
+        when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
+
+        Client toCreate = new Client();
+        toCreate.setDomain(DOMAIN);
+        toCreate.setAuthorizedGrantTypes(Arrays.asList("implicit"));
+        toCreate.setResponseTypes(Arrays.asList("token"));
+        TestObserver testObserver = clientService.create(toCreate).test();
+        testObserver.awaitTerminalEvent();
 
+        testObserver.assertNotComplete();
+        testObserver.assertError(InvalidRedirectUriException.class);
+    }
+
+    @Test
+    public void create_generateUuidAsClientId() {
         when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
         when(domainService.reload(eq(DOMAIN), any())).thenReturn(Single.just(new Domain()));
         when(scopeService.validateScope(DOMAIN,null)).thenReturn(Single.just(true));
-        when(clientRepository.create(any(Client.class))).thenReturn(Single.just(createClient));
+        when(clientRepository.create(any(Client.class))).thenReturn(Single.just(new Client()));
 
         Client toCreate = new Client();
         toCreate.setDomain(DOMAIN);
+        toCreate.setRedirectUris(Arrays.asList("https://callback"));
         TestObserver testObserver = clientService.create(toCreate).test();
         testObserver.awaitTerminalEvent();
 
@@ -441,11 +469,14 @@ public class ClientServiceTest {
     }
 
     @Test
-    public void shouldUpdate() {
+    public void shouldPatch_keepingClientRedirectUris() {
         PatchClient patchClient = new PatchClient();
         patchClient.setIdentities(Optional.of(new HashSet<>(Arrays.asList("id1", "id2"))));
         patchClient.setAuthorizedGrantTypes(Optional.of(Arrays.asList("authorization_code")));
-        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(new Client()));
+        Client toPatch = new Client();
+        toPatch.setDomain(DOMAIN);
+        toPatch.setRedirectUris(Arrays.asList("https://callback"));
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(toPatch));
         when(identityProviderService.findById("id1")).thenReturn(Maybe.just(new IdentityProvider()));
         when(identityProviderService.findById("id2")).thenReturn(Maybe.just(new IdentityProvider()));
         when(clientRepository.update(any(Client.class))).thenReturn(Single.just(new Client()));
@@ -464,6 +495,26 @@ public class ClientServiceTest {
         verify(clientRepository, times(1)).update(any(Client.class));
     }
 
+    @Test
+    public void shouldUpdate_implicit_invalidRedirectUri() {
+        Client client = new Client();
+        client.setDomain(DOMAIN);
+        PatchClient patchClient = new PatchClient();
+        patchClient.setAuthorizedGrantTypes(Optional.of(Arrays.asList("implicit")));
+        patchClient.setResponseTypes(Optional.of(Arrays.asList("token")));
+
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(client));
+        when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
+
+        TestObserver testObserver = clientService.patch(DOMAIN, "my-client", patchClient).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertNotComplete();
+        testObserver.assertError(InvalidRedirectUriException.class);
+
+        verify(clientRepository, times(1)).findById(anyString());
+    }
+
     @Test
     public void shouldUpdate_technicalException() {
         PatchClient patchClient = Mockito.mock(PatchClient.class);
@@ -526,10 +577,27 @@ public class ClientServiceTest {
         testObserver.assertError(InvalidClientMetadataException.class);
     }
 
-
     @Test
-    public void update_ok() {
+    public void update_implicitGrant_invalidRedirectUri() {
+
+        when(clientRepository.findById(any())).thenReturn(Maybe.just(new Client()));
+        when(domainService.findById(any())).thenReturn(Maybe.just(new Domain()));
+
+        Client toUpdate = new Client();
+        toUpdate.setAuthorizedGrantTypes(Arrays.asList("implicit"));
+        toUpdate.setResponseTypes(Arrays.asList("token"));
+        toUpdate.setDomain(DOMAIN);
+        TestObserver testObserver = clientService.update(toUpdate).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertNotComplete();
+        testObserver.assertError(InvalidRedirectUriException.class);
 
+        verify(clientRepository, times(1)).findById(any());
+    }
+
+    @Test
+    public void update_defaultGrant_ok() {
         when(clientRepository.findById(any())).thenReturn(Maybe.just(new Client()));
         when(clientRepository.update(any(Client.class))).thenReturn(Single.just(new Client()));
         when(domainService.findById(any())).thenReturn(Maybe.just(new Domain()));
@@ -538,6 +606,7 @@ public class ClientServiceTest {
 
         Client toUpdate = new Client();
         toUpdate.setDomain(DOMAIN);
+        toUpdate.setRedirectUris(Arrays.asList("https://callback"));
         TestObserver testObserver = clientService.update(toUpdate).test();
         testObserver.awaitTerminalEvent();
 
@@ -548,15 +617,95 @@ public class ClientServiceTest {
         verify(clientRepository, times(1)).update(any(Client.class));
     }
 
+    @Test
+    public void update_clientCredentials_ok() {
+        when(clientRepository.findById(any())).thenReturn(Maybe.just(new Client()));
+        when(clientRepository.update(any(Client.class))).thenReturn(Single.just(new Client()));
+        when(domainService.findById(any())).thenReturn(Maybe.just(new Domain()));
+        when(domainService.reload(any(), any())).thenReturn(Single.just(new Domain()));
+        when(scopeService.validateScope(any(),any())).thenReturn(Single.just(true));
+
+        Client toUpdate = new Client();
+        toUpdate.setDomain(DOMAIN);
+        toUpdate.setAuthorizedGrantTypes(Arrays.asList("client_credentials"));
+        toUpdate.setResponseTypes(Arrays.asList());
+        TestObserver testObserver = clientService.update(toUpdate).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+
+        verify(clientRepository, times(1)).findById(any());
+        verify(clientRepository, times(1)).update(any(Client.class));
+    }
 
     @Test
     public void shouldPatch() {
-        PatchClient patchClient = Mockito.mock(PatchClient.class);
-        when(patchClient.patch(any(), eq(false))).thenReturn(new Client());
+        Client client = new Client();
+        client.setDomain(DOMAIN);
+
+        PatchClient patchClient = new PatchClient();
+        patchClient.setIdentities(Optional.of(new HashSet<>(Arrays.asList("id1", "id2"))));
+        patchClient.setAuthorizedGrantTypes(Optional.of(Arrays.asList("authorization_code")));
+        patchClient.setRedirectUris(Optional.of(Arrays.asList("https://callback")));
+
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(client));
+        when(identityProviderService.findById("id1")).thenReturn(Maybe.just(new IdentityProvider()));
+        when(identityProviderService.findById("id2")).thenReturn(Maybe.just(new IdentityProvider()));
+        when(clientRepository.update(any(Client.class))).thenReturn(Single.just(new Client()));
         when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
         when(domainService.reload(eq(DOMAIN), any())).thenReturn(Single.just(new Domain()));
-        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(new Client()));
+        when(scopeService.validateScope(DOMAIN,null)).thenReturn(Single.just(true));
+
+        TestObserver testObserver = clientService.patch(DOMAIN, "my-client", patchClient).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+
+        verify(clientRepository, times(1)).findById(anyString());
+        verify(identityProviderService, times(2)).findById(anyString());
+        verify(clientRepository, times(1)).update(any(Client.class));
+    }
+
+    @Test
+    public void shouldPatch_mobileApplication() {
+        Client client = new Client();
+        client.setDomain(DOMAIN);
+
+        PatchClient patchClient = new PatchClient();
+        patchClient.setAuthorizedGrantTypes(Optional.of(Arrays.asList("authorization_code")));
+        patchClient.setRedirectUris(Optional.of(Arrays.asList("com.gravitee.app://callback")));
+
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(client));
         when(clientRepository.update(any(Client.class))).thenReturn(Single.just(new Client()));
+        when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
+        when(domainService.reload(eq(DOMAIN), any())).thenReturn(Single.just(new Domain()));
+        when(scopeService.validateScope(DOMAIN,null)).thenReturn(Single.just(true));
+
+        TestObserver testObserver = clientService.patch(DOMAIN, "my-client", patchClient).test();
+        testObserver.awaitTerminalEvent();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+
+        verify(clientRepository, times(1)).findById(anyString());
+        verify(clientRepository, times(1)).update(any(Client.class));
+    }
+
+    @Test
+    public void shouldPatch_mobileApplication_googleCase() {
+        Client client = new Client();
+        client.setDomain(DOMAIN);
+
+        PatchClient patchClient = new PatchClient();
+        patchClient.setAuthorizedGrantTypes(Optional.of(Arrays.asList("authorization_code")));
+        patchClient.setRedirectUris(Optional.of(Arrays.asList("com.google.app:/callback")));
+
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(client));
+        when(clientRepository.update(any(Client.class))).thenReturn(Single.just(new Client()));
+        when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
+        when(domainService.reload(eq(DOMAIN), any())).thenReturn(Single.just(new Domain()));
         when(scopeService.validateScope(DOMAIN,null)).thenReturn(Single.just(true));
 
         TestObserver testObserver = clientService.patch(DOMAIN, "my-client", patchClient).test();
@@ -656,10 +805,47 @@ public class ClientServiceTest {
         verify(clientRepository, never()).delete("my-client");
     }
 
+    @Test
+    public void validateClientMetadata_invalidRedirectUriException_noSchemeUri() {
+        PatchClient patchClient = Mockito.mock(PatchClient.class);
+        Client client = new Client();
+        client.setDomain(DOMAIN);
+        client.setRedirectUris(Arrays.asList("noscheme"));
+        when(patchClient.patch(any(), anyBoolean())).thenReturn(client);
+        when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(new Client()));
+
+        TestObserver testObserver = clientService.patch(DOMAIN, "my-client", patchClient).test();
+        testObserver.assertError(InvalidRedirectUriException.class);
+        testObserver.assertNotComplete();
+
+        verify(clientRepository, times(1)).findById(anyString());
+        verify(clientRepository, never()).update(any(Client.class));
+    }
+
+    @Test
+    public void validateClientMetadata_invalidRedirectUriException_malformedUri() {
+        PatchClient patchClient = Mockito.mock(PatchClient.class);
+        Client client = new Client();
+        client.setDomain(DOMAIN);
+        client.setRedirectUris(Arrays.asList("malformed:uri:exception"));
+        when(patchClient.patch(any(), anyBoolean())).thenReturn(client);
+        when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(new Client()));
+
+        TestObserver testObserver = clientService.patch(DOMAIN, "my-client", patchClient).test();
+        testObserver.assertError(InvalidRedirectUriException.class);
+        testObserver.assertNotComplete();
+
+        verify(clientRepository, times(1)).findById(anyString());
+        verify(clientRepository, never()).update(any(Client.class));
+    }
+
     @Test
     public void validateClientMetadata_invalidRedirectUriException_forbidLocalhost() {
         PatchClient patchClient = Mockito.mock(PatchClient.class);
         Client client = new Client();
+        client.setDomain(DOMAIN);
         client.setRedirectUris(Arrays.asList("http://localhost/callback"));
         when(patchClient.patch(any(), anyBoolean())).thenReturn(client);
         when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
@@ -677,6 +863,7 @@ public class ClientServiceTest {
     public void validateClientMetadata_invalidRedirectUriException_forbidHttp() {
         PatchClient patchClient = Mockito.mock(PatchClient.class);
         Client client = new Client();
+        client.setDomain(DOMAIN);
         client.setRedirectUris(Arrays.asList("http://gravitee.io/callback"));
         when(patchClient.patch(any(), anyBoolean())).thenReturn(client);
         when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
@@ -694,6 +881,7 @@ public class ClientServiceTest {
     public void validateClientMetadata_invalidRedirectUriException_forbidWildcard() {
         PatchClient patchClient = Mockito.mock(PatchClient.class);
         Client client = new Client();
+        client.setDomain(DOMAIN);
         client.setRedirectUris(Arrays.asList("https://gravitee.io/*"));
         when(patchClient.patch(any(), anyBoolean())).thenReturn(client);
         when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
@@ -711,6 +899,8 @@ public class ClientServiceTest {
     public void validateClientMetadata_invalidClientMetadataException_unknownScope() {
         PatchClient patchClient = Mockito.mock(PatchClient.class);
         Client client = new Client();
+        client.setDomain(DOMAIN);
+        client.setRedirectUris(Arrays.asList("https://callback"));
         client.setScopes(Collections.emptyList());
         when(patchClient.patch(any(), anyBoolean())).thenReturn(client);
         when(domainService.findById(DOMAIN)).thenReturn(Maybe.just(new Domain()));
@@ -729,6 +919,7 @@ public class ClientServiceTest {
     public void validateClientMetadata_validMetadata() {
         PatchClient patchClient = Mockito.mock(PatchClient.class);
         Client client = new Client();
+        client.setDomain(DOMAIN);
         client.setRedirectUris(Arrays.asList("https://gravitee.io/callback"));
         client.setScopes(Collections.emptyList());
         when(patchClient.patch(any(), anyBoolean())).thenReturn(client);
@@ -750,9 +941,12 @@ public class ClientServiceTest {
 
     @Test
     public void shouldRenewSecret() {
+        Client client = Mockito.mock(Client.class);
+
+        when(client.getDomain()).thenReturn(DOMAIN);
         when(domainService.reload(eq(DOMAIN), any())).thenReturn(Single.just(new Domain()));
-        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(new Client()));
-        when(clientRepository.update(any(Client.class))).thenReturn(Single.just(new Client()));
+        when(clientRepository.findById("my-client")).thenReturn(Maybe.just(client));
+        when(clientRepository.update(any(Client.class))).thenReturn(Single.just(client));
 
         TestObserver testObserver = clientService.renewClientSecret(DOMAIN, "my-client").test();
         testObserver.awaitTerminalEvent();
diff --git a/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/GrantTypeUtilsTest.java b/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/GrantTypeUtilsTest.java
index e4b4d3758e..6ac38a4640 100644
--- a/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/GrantTypeUtilsTest.java
+++ b/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/GrantTypeUtilsTest.java
@@ -16,14 +16,15 @@
 package io.gravitee.am.service.utils;
 
 import io.gravitee.am.model.Client;
+import io.gravitee.am.service.exception.InvalidClientMetadataException;
+import io.reactivex.observers.TestObserver;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 import java.util.Arrays;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 /**
  * @author Alexandre FARIA (contact at alexandrefaria.net)
@@ -33,21 +34,104 @@ import static org.junit.Assert.assertTrue;
 public class GrantTypeUtilsTest {
 
     @Test
-    public void isValidGrantType_authorization_code_implicit_refresh_token() {
-        boolean isValid = GrantTypeUtils.isValidGrantType(Arrays.asList("authorization_code", "implicit", "refresh_token"));
-        assertTrue("Were expecting to be true",isValid);
+    public void validateGrantTypes_nullClient() {
+        TestObserver<Client> testObserver = GrantTypeUtils.validateGrantTypes(null).test();
+
+        testObserver.assertNotComplete();
+        testObserver.assertError(InvalidClientMetadataException.class);
+    }
+
+    @Test
+    public void validateGrantTypes_authorization_code_implicit_refresh_token() {
+        Client client = new Client();
+        client.setAuthorizedGrantTypes(Arrays.asList("authorization_code", "implicit", "refresh_token"));
+
+        TestObserver<Client> testObserver = GrantTypeUtils.validateGrantTypes(client).test();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+    }
+
+    @Test
+    public void validateGrantTypes_unknown_grant_type() {
+        Client client = new Client();
+        client.setAuthorizedGrantTypes(Arrays.asList("unknown"));
+
+        TestObserver<Client> testObserver = GrantTypeUtils.validateGrantTypes(client).test();
+
+        testObserver.assertNotComplete();
+        testObserver.assertError(InvalidClientMetadataException.class);
+    }
+
+    @Test
+    public void validateGrantTypes_empty_grant_type() {
+        Client client = new Client();
+        client.setAuthorizedGrantTypes(Arrays.asList());
+
+        TestObserver<Client> testObserver = GrantTypeUtils.validateGrantTypes(client).test();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+    }
+
+    @Test
+    public void validateGrantTypes_refreshToken_nok() {
+        Client client = new Client();
+        client.setAuthorizedGrantTypes(Arrays.asList("refresh_token","implicit"));
+        client.setResponseTypes(Arrays.asList("token"));
+
+        TestObserver<Client> testObserver = GrantTypeUtils.validateGrantTypes(client).test();
+
+        testObserver.assertNotComplete();
+        testObserver.assertError(InvalidClientMetadataException.class);
+    }
+
+    @Test
+    public void validateGrantTypes_refreshToken_client_credentials_nok() {
+        Client client = new Client();
+        client.setAuthorizedGrantTypes(Arrays.asList("refresh_token","client_credentials"));
+        client.setResponseTypes(Arrays.asList());
+
+        TestObserver<Client> testObserver = GrantTypeUtils.validateGrantTypes(client).test();
+
+        testObserver.assertNotComplete();
+        testObserver.assertError(InvalidClientMetadataException.class);
     }
 
     @Test
-    public void isValidGrantType_unknown_response_type() {
-        boolean isValid = GrantTypeUtils.isValidGrantType(Arrays.asList("unknown"));
-        assertFalse("Were expecting to be false",isValid);
+    public void validateGrantTypes_refreshToken_ok() {
+        Client client = new Client();
+        client.setAuthorizedGrantTypes(Arrays.asList("refresh_token","authorization_code"));
+
+        TestObserver<Client> testObserver = GrantTypeUtils.validateGrantTypes(client).test();
+
+        testObserver.assertComplete();
+        testObserver.assertNoErrors();
+    }
+
+    @Test
+    public void isSupportedGrantType_empty_grant_type() {
+        boolean isSupportedGrantType = GrantTypeUtils.isSupportedGrantType(Arrays.asList());
+        assertFalse("Were expecting to be false",isSupportedGrantType);
     }
 
     @Test
-    public void isValidGrantType_empty_response_type() {
-        boolean isValid = GrantTypeUtils.isValidGrantType(Arrays.asList());
-        assertFalse("Were expecting to be false",isValid);
+    public void supportedGrantTypes() {
+        assertTrue("should have at least authorization_code", GrantTypeUtils.getSupportedGrantTypes().contains("authorization_code"));
+    }
+
+    @Test
+    public void isRedirectUriRequired() {
+        //isRedirectUriRequired("authorization_code",true);//should be true for mobile app, false for web app...
+        isRedirectUriRequired("implicit",true);
+        //isRedirectUriRequired("hybrid",true);
+        isRedirectUriRequired("password",false);
+        isRedirectUriRequired("client_credentials",false);
+    }
+
+    private void isRedirectUriRequired(String grant, boolean expected) {
+        boolean isValid = GrantTypeUtils.isRedirectUriRequired(Arrays.asList(grant));
+        assertEquals("not expected result for "+grant,expected, isValid);
     }
 
     @Test
diff --git a/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/ResponseTypeUtilsTest.java b/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/ResponseTypeUtilsTest.java
index bed48757df..2667299b02 100644
--- a/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/ResponseTypeUtilsTest.java
+++ b/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/ResponseTypeUtilsTest.java
@@ -21,9 +21,9 @@ import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 import java.util.Arrays;
+import java.util.List;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 /**
  * @author Alexandre FARIA (contact at alexandrefaria.net)
@@ -34,7 +34,7 @@ public class ResponseTypeUtilsTest {
 
     @Test
     public void test_code_token_id_token() {
-        boolean isValid = ResponseTypeUtils.isValidResponseType(Arrays.asList(
+        boolean isValid = ResponseTypeUtils.isSupportedResponseType(Arrays.asList(
                 "code", "token", "id_token",
                 "id_token token", "code token", "code id_token","code id_token token")
         );
@@ -43,16 +43,21 @@ public class ResponseTypeUtilsTest {
 
     @Test
     public void test_unknown_response_type() {
-        boolean isValid = ResponseTypeUtils.isValidResponseType(Arrays.asList("code token id_token"));
+        boolean isValid = ResponseTypeUtils.isSupportedResponseType(Arrays.asList("code token id_token"));
         assertFalse("Were expecting to be false",isValid);
     }
 
     @Test
     public void test_empty_response_type() {
-        boolean isValid = ResponseTypeUtils.isValidResponseType(Arrays.asList());
-        assertFalse("Were expecting to be false",isValid);
+        boolean isValid = ResponseTypeUtils.isSupportedResponseType(Arrays.asList());
+        assertTrue("Were expecting to be true",isValid);//Can be empty for client_credentials...
     }
 
+    @Test
+    public void test_null_response_type() {
+        boolean isValid = ResponseTypeUtils.isSupportedResponseType((List<String>)null);
+        assertFalse("Were expecting to be false",isValid);//Can be empty for client_credentials...
+    }
     @Test
     public void applyDefaultResponseType() {
         Client client = new Client();
@@ -99,4 +104,10 @@ public class ResponseTypeUtilsTest {
         assertTrue(ResponseTypeUtils.requireNonce("id_token"));
         assertTrue(ResponseTypeUtils.requireNonce("id_token token"));
     }
+
+    @Test
+    public void supportedResponseTypes() {
+        assertTrue("should have at least code", ResponseTypeUtils.getSupportedResponseTypes().contains("code"));
+        assertTrue("should have at least token", ResponseTypeUtils.getSupportedResponseTypes().contains("token"));
+    }
 }
diff --git a/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/UriBuilderTest.java b/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/UriBuilderTest.java
index ecd7ab8c08..6317844254 100644
--- a/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/UriBuilderTest.java
+++ b/gravitee-am-service/src/test/java/io/gravitee/am/service/utils/UriBuilderTest.java
@@ -23,6 +23,7 @@ import org.junit.runners.Parameterized;
 import java.net.URI;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.StringJoiner;
 
 import static org.junit.runners.Parameterized.Parameters;
 
@@ -41,8 +42,9 @@ public class UriBuilderTest {
     private String path;
     private String query;
     private String fragment;
+    private boolean isHttp;
 
-    public UriBuilderTest(String uri, int port, String[] params) {
+    public UriBuilderTest(String uri, int port, String[] params, boolean isHttp) {
         this.uri = uri;
         this.port = port;
         this.scheme = params[0];
@@ -51,18 +53,19 @@ public class UriBuilderTest {
         this.path = params[3];
         this.query = params[4];
         this.fragment = params[5];
+        this.isHttp = isHttp;
     }
 
     @Parameters(name="Testing {0}")
     public static Collection<Object[]> data() {
         return Arrays.asList(new Object[][] {
-                {"http://localhost:8080/callback",8080,Arrays.asList("http","localhost",null,"/callback",null,null).toArray(new String[8])},
-                {"https://admin:password@localhost/callback",-1,Arrays.asList("https","localhost","admin:password","/callback",null,null).toArray(new String[8])},
-                {"https://gravitee.is?the=best",-1,Arrays.asList("https","gravitee.is",null,"","the=best",null).toArray(new String[8])},
-                {"myapp://callback#token=fragment",-1,Arrays.asList("myapp","callback",null,"",null,"token=fragment").toArray(new String[8])},
+                {"http://localhost:8080/callback",8080,Arrays.asList("http","localhost",null,"/callback",null,null).toArray(new String[6]),true},
+                {"https://admin:password@localhost/callback",-1,Arrays.asList("https","localhost","admin:password","/callback",null,null).toArray(new String[6]),true},
+                {"https://gravitee.is?the=best",-1,Arrays.asList("https","gravitee.is",null,"","the=best",null).toArray(new String[6]),true},
+                {"myapp://callback#token=fragment",-1,Arrays.asList("myapp","callback",null,"",null,"token=fragment").toArray(new String[6]),false},
                 {"https://op-test:60001/requests/something?the=best#fragment",60001,
-                        Arrays.asList("https","op-test",null,"/requests/something","the=best","fragment").toArray(new String[8])}
-
+                        Arrays.asList("https","op-test",null,"/requests/something","the=best","fragment").toArray(new String[6]),true},
+                {"com.google.app:/callback",-1,Arrays.asList("com.google.app",null,null,"/callback",null,null).toArray(new String[6]),false}
         });
     }
 
@@ -76,11 +79,12 @@ public class UriBuilderTest {
         Assert.assertEquals("path",this.path,uri.getPath());
         Assert.assertEquals("query",this.query,uri.getQuery());
         Assert.assertEquals("fragment",this.fragment,uri.getFragment());
+        Assert.assertEquals("Scheme isHttp does not match",this.isHttp, UriBuilder.isHttp(uri.getScheme()));
     }
 
     @Test
     public void testFromHttp() throws Exception{
-        if(this.uri.trim().startsWith("http")) {
+        if(this.isHttp) {
             URI uri = UriBuilder.fromHttpUrl(this.uri).build();
             Assert.assertEquals("scheme",this.scheme,uri.getScheme());
             Assert.assertEquals("user info",this.userinfo,uri.getUserInfo());
@@ -89,10 +93,11 @@ public class UriBuilderTest {
             Assert.assertEquals("path",this.path,uri.getPath());
             Assert.assertEquals("query",this.query,uri.getQuery());
             Assert.assertEquals("fragment",this.fragment,uri.getFragment());
+            Assert.assertEquals("Scheme isHttp does not match",this.isHttp, UriBuilder.isHttp(uri.getScheme()));
         }else {
             boolean assertThrowException = false;
             try {
-                URI uri = UriBuilder.fromHttpUrl(this.uri).build();
+                UriBuilder.fromHttpUrl(this.uri).build();
             } catch (IllegalArgumentException ex) {
                 assertThrowException = true;
             }