浏览代码

Polish gh-1320

Joe Grandja 1 年之前
父节点
当前提交
3eb951f59d

+ 45 - 59
docs/modules/ROOT/pages/guides/how-to-dynamic-client-registration.adoc

@@ -3,60 +3,50 @@
 :index-link: ../how-to.html
 :docs-dir: ..
 
-This guide shows how to configure OpenID Connect Dynamic Client Registration 1.0 in Spring Authorization Server and walks through an example of how to register a client.
-Spring Authorization Server implements https://openid.net/specs/openid-connect-registration-1_0.html[OpenID Connect Dynamic Client Registration 1.0]
-specification, gaining the ability to dynamically register and retrieve OpenID clients.
+This guide shows how to configure OpenID Connect Dynamic Client Registration in Spring Authorization Server and walks through an example of how to register a client.
+Spring Authorization Server implements the https://openid.net/specs/openid-connect-registration-1_0.html[OpenID Connect Dynamic Client Registration 1.0] specification, providing the capability to dynamically register and retrieve OpenID Connect clients.
 
-- xref:guides/how-to-dynamic-client-registration.adoc#enable[Enable Dynamic Client Registration]
-- xref:guides/how-to-dynamic-client-registration.adoc#configure-initial-client[Configure initial client]
-- xref:guides/how-to-dynamic-client-registration.adoc#obtain-initial-access-token[Obtain initial access token]
-- xref:guides/how-to-dynamic-client-registration.adoc#register-client[Register a client]
+* xref:guides/how-to-dynamic-client-registration.adoc#enable-dynamic-client-registration[Enable Dynamic Client Registration]
+* xref:guides/how-to-dynamic-client-registration.adoc#configure-client-registrar[Configure client registrar]
+* xref:guides/how-to-dynamic-client-registration.adoc#obtain-initial-access-token[Obtain initial access token]
+* xref:guides/how-to-dynamic-client-registration.adoc#register-client[Register a client]
 
-[[enable]]
+[[enable-dynamic-client-registration]]
 == Enable Dynamic Client Registration
 
 By default, dynamic client registration functionality is disabled in Spring Authorization Server.
 To enable, add the following configuration:
 
-[[sample.dcrAuthServerConfig]]
+[[sample.SecurityConfig]]
 [source,java]
 ----
-include::{examples-dir}/main/java/sample/dcr/DcrConfiguration.java[]
+include::{examples-dir}/main/java/sample/registration/SecurityConfig.java[]
 ----
 
-<1> Add a `SecurityFilterChain` `@Bean` that registers an `OAuth2AuthorizationServerConfigurer`
-<2> In the configurer, apply OIDC client registration endpoint customizer with default values.
-This enables dynamic client registration functionality.
+<1> Enable the xref:protocol-endpoints.adoc#oidc-client-registration-endpoint[OpenID Connect 1.0 Client Registration Endpoint] with the default configuration.
 
-Please refer to xref:protocol-endpoints.adoc#oidc-client-registration-endpoint[Client Registration Endpoint docs] for in-depth configuration details.
+[[configure-client-registrar]]
+== Configure client registrar
 
-[[configure-initial-client]]
-== Configure initial client
+An existing client is used to register new clients with the authorization server.
+The client must be configured with scopes `client.create` and optionally `client.read` for registering clients and retrieving clients, respectively.
+The following listing shows an example client:
 
-An initial client is required in order to register new clients in the authorization server.
-The client must be configured with scopes `client.create` and optionally `client.read` for creating clients and reading clients, respectively.
-A programmatic example of such a client is below.
-
-[[sample.dcrRegisteredClientConfig]]
+[[sample.ClientConfig]]
 [source,java]
 ----
-include::{examples-dir}/main/java/sample/dcr/RegisteredClientConfiguration.java[]
+include::{examples-dir}/main/java/sample/registration/ClientConfig.java[]
 ----
 
-<1> A `RegisteredClientRepository` `@Bean` is configured with a set of clients.
-<2> An initial client with client id `dcr-client` is configured.
-<3> `client_credentials` grant type is set to fetch access tokens directly.
-<4> `client.create` scope is configured for the client to ensure they are able to create clients.
-<5> `client.read` scope is configured for the client to ensure they are able to fetch and read clients.
-<6> The initial client is saved into the data store.
-
-After configuring the above, run the authorization server in your preferred environment.
+<1> `client_credentials` grant type is configured to obtain access tokens directly.
+<2> `client.create` scope is configured to allow the client to register a new client.
+<3> `client.read` scope is configured to allow the client to retrieve a registered client.
 
 [[obtain-initial-access-token]]
 == Obtain initial access token
 
-An initial access token is required to be able to create client registration requests.
-The token request must contain a request for scope `client.create` only.
+An "initial" access token is required for the client registration request.
+The access token request *MUST* contain the `scope` parameter value `client.create` only.
 
 [source,httprequest]
 ----
@@ -69,18 +59,18 @@ grant_type=client_credentials&scope=client.create
 
 [WARNING]
 ====
-If you provide more than one scope in the request, you will not be able to register a client.
-The client creation request requires an access token with a single scope of `client.create`
+The client registration request requires an access token with a single scope of `client.create`.
+If the access token contains additional scope, the client registration request will be denied.
 ====
 
 [TIP]
 ====
-To obtain encoded credentials for the above request, `base64` encode the client credentials in the format of
-`<clientId>:<clientSecret>`. Below is an encoding operation for the example in this guide.
+To obtain encoded credentials for the above request, `base64` encode the client credentials in the format of `<clientId>:<clientSecret>`.
+Below is an encoding operation for the example in this guide.
 
 [source,console]
 ----
-echo -n "initial-app:secret" | base64
+echo -n "registrar-client:secret" | base64
 ----
 ====
 
@@ -90,30 +80,26 @@ echo -n "initial-app:secret" | base64
 With an access token obtained from the previous step, a client can now be dynamically registered.
 
 [NOTE]
-The access token can only be used once. After a single registration request, the access token is invalidated.
+The "initial" access token can only be used once.
+After the client is registered, the access token is invalidated.
 
-[[sample.dcrClientRegistration]]
+[[sample.ClientRegistrar]]
 [source,java]
 ----
-include::{examples-dir}/main/java/sample/dcr/DcrClient.java[]
+include::{examples-dir}/main/java/sample/registration/ClientRegistrar.java[]
 ----
 
-<1> A minimal client registration request object.
-You may add additional fields as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationRequest[OpenID Connect Dynamic Client Registration 1.0 spec - Client Registration Request].
-<2> A minimal client registration response object.
-You may add additional response fields as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse[OpenID Connect Dynamic Client Registration 1.0 spec - Client Registration Response].
-<3> A sample client registration request object which will be used to register a sample client.
-<4> Example dynamic client registration procedure, demonstrating dynamic registration and client retrieval.
-<5> Register a client using sample request from step 2, using initial access token from previous step.
-Skip to step 10 for implementation.
-<6> After registration, assert on the fields that should be populated in the response upon successful registration.
-<7> Extract `registration_access_token` and `registration_client_uri` fields, for use in retrieval of the newly registered client.
-<8> Retrieve client. Skip to step 11 for implementation.
-<9> After client retrieval, assert on the fields that should be populated in the response.
-<10> Sample client registration procedure using Spring WebFlux's `WebClient`.
-Note that the `WebClient` must have `baseUrl` of the authorization server configured.
-<11> Sample client retrieval procedure using Spring WebFlux's `WebClient`.
-Note that the `WebClient` must have `baseUrl` of the authorization server configured.
-
-The retrieve client response should contain the same information about the client as seen when the client was first
-registered, except for `registration_access_token` field.
+<1> A minimal representation of a client registration request. You may add additional client metadata parameters as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationRequest[Client Registration Request].
+<2> A minimal representation of a client registration response. You may add additional client metadata parameters as per https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse[Client Registration Response].
+<3> Example demonstrating client registration and client retrieval.
+<4> A sample client registration request object.
+<5> Register the client using the "initial" access token and client registration request object.
+<6> After successful registration, assert on the client metadata parameters that should be populated in the response.
+<7> Extract `registration_access_token` and `registration_client_uri` response parameters, for use in retrieval of the newly registered client.
+<8> Retrieve the client using the `registration_access_token` and `registration_client_uri`.
+<9> After client retrieval, assert on the client metadata parameters that should be populated in the response.
+<10> Sample https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationRequest[Client Registration Request] using `WebClient`.
+<11> Sample https://openid.net/specs/openid-connect-registration-1_0.html#ReadRequest[Client Read Request] using `WebClient`.
+
+[NOTE]
+The https://openid.net/specs/openid-connect-registration-1_0.html#ReadResponse[Client Read Response] should contain the same client metadata parameters as the https://openid.net/specs/openid-connect-registration-1_0.html#RegistrationResponse[Client Registration Response], except the `registration_access_token` parameter.

+ 0 - 96
docs/src/main/java/sample/dcr/DcrConfiguration.java

@@ -1,96 +0,0 @@
-/*
- * Copyright 2020-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package sample.dcr;
-
-import com.nimbusds.jose.jwk.JWKSet;
-import com.nimbusds.jose.jwk.RSAKey;
-import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
-import com.nimbusds.jose.jwk.source.JWKSource;
-import com.nimbusds.jose.proc.SecurityContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.config.Customizer;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.oauth2.jwt.JwtDecoder;
-import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
-import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
-import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
-import org.springframework.security.provisioning.InMemoryUserDetailsManager;
-import org.springframework.security.web.SecurityFilterChain;
-
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-import java.util.Collections;
-import java.util.UUID;
-
-@Configuration
-@EnableWebSecurity
-public class DcrConfiguration {
-	@Bean // <1>
-	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
-		OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
-		http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
-				.oidc(oidc -> oidc.clientRegistrationEndpoint(Customizer.withDefaults())); // <2>
-		http.oauth2ResourceServer(oauth2ResourceServer ->
-				oauth2ResourceServer.jwt(Customizer.withDefaults()));
-
-		return http.build();
-	}
-	// @fold:on
-
-	@Bean
-	public UserDetailsService userDetailsService() {
-		// This example uses client credentials grant type - no need for any users.
-		return new InMemoryUserDetailsManager(Collections.emptyList());
-	}
-
-	@Bean
-	public JWKSource<SecurityContext> jwkSource() {
-		// @formatter:off
-		KeyPair keyPair;
-		try {
-			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
-			keyPairGenerator.initialize(2048);
-			keyPair = keyPairGenerator.generateKeyPair();
-		} catch (Exception ex) {
-			throw new IllegalStateException(ex);
-		}
-		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
-		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
-		RSAKey rsaKey = new RSAKey.Builder(publicKey)
-				.privateKey(privateKey)
-				.keyID(UUID.randomUUID().toString())
-				.build();
-		// @formatter:on
-		JWKSet jwkSet = new JWKSet(rsaKey);
-		return new ImmutableJWKSet<>(jwkSet);
-	}
-
-	@Bean
-	public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
-		return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
-	}
-
-	@Bean
-	public AuthorizationServerSettings authorizationServerSettings() {
-		return AuthorizationServerSettings.builder().build();
-	}
-	// @fold:off
-}

+ 13 - 11
docs/src/main/java/sample/dcr/RegisteredClientConfiguration.java → docs/src/main/java/sample/registration/ClientConfig.java

@@ -13,7 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package sample.dcr;
+package sample.registration;
+
+import java.util.UUID;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -23,21 +25,21 @@ import org.springframework.security.oauth2.server.authorization.client.InMemoryR
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 
-import java.util.UUID;
-
 @Configuration
-public class RegisteredClientConfiguration {
-	@Bean // <1>
+public class ClientConfig {
+
+	@Bean
 	public RegisteredClientRepository registeredClientRepository() {
-		RegisteredClient initialClient = RegisteredClient.withId(UUID.randomUUID().toString())
-				.clientId("dcr-client") // <2>
+		RegisteredClient registrarClient = RegisteredClient.withId(UUID.randomUUID().toString())
+				.clientId("registrar-client")
 				.clientSecret("{noop}secret")
 				.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
-				.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) // <3>
-				.scope("client.create") // <4>
-				.scope("client.read") // <5>
+				.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)	// <1>
+				.scope("client.create")	// <2>
+				.scope("client.read")	// <3>
 				.build();
 
-		return new InMemoryRegisteredClientRepository(initialClient); // <6>
+		return new InMemoryRegisteredClientRepository(registrarClient);
 	}
+
 }

+ 31 - 27
docs/src/main/java/sample/dcr/DcrClient.java → docs/src/main/java/sample/registration/ClientRegistrar.java

@@ -13,56 +13,58 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package sample.dcr;
+package sample.registration;
+
+import java.util.List;
+import java.util.Objects;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
+import reactor.core.publisher.Mono;
+
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Mono;
 
-import java.util.List;
-import java.util.Objects;
-
-public class DcrClient {
+public class ClientRegistrar {
 	// @fold:on
 	private final WebClient webClient;
 
-	public DcrClient(final WebClient webClient) {
+	public ClientRegistrar(WebClient webClient) {
 		this.webClient = webClient;
 	}
 	// @fold:off
 
-	public record DcrRequest( // <1>
+	public record ClientRegistrationRequest(	// <1>
 			@JsonProperty("client_name") String clientName,
 			@JsonProperty("grant_types") List<String> grantTypes,
 			@JsonProperty("redirect_uris") List<String> redirectUris,
 			String scope) {
 	}
 
-	public record DcrResponse( // <2>
+	public record ClientRegistrationResponse(	// <2>
 			@JsonProperty("registration_access_token") String registrationAccessToken,
 			@JsonProperty("registration_client_uri") String registrationClientUri,
 			@JsonProperty("client_name") String clientName,
+			@JsonProperty("client_id") String clientId,
 			@JsonProperty("client_secret") String clientSecret,
 			@JsonProperty("grant_types") List<String> grantTypes,
 			@JsonProperty("redirect_uris") List<String> redirectUris,
 			String scope) {
 	}
 
-	public static final DcrRequest SAMPLE_CLIENT_REGISTRATION_REQUEST = new DcrRequest( // <3>
-			"client-1",
-			List.of(AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
-			List.of("https://client.example.org/callback", "https://client.example.org/callback2"),
-			"openid email profile"
-	);
+	public void exampleRegistration(String initialAccessToken) {	// <3>
+		ClientRegistrationRequest clientRegistrationRequest = new ClientRegistrationRequest(	// <4>
+				"client-1",
+				List.of(AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
+				List.of("https://client.example.org/callback", "https://client.example.org/callback2"),
+				"openid email profile"
+		);
 
-	public void exampleRegistration(String initialAccessToken) { // <4>
-		DcrResponse clientRegistrationResponse =
-				this.registerClient(initialAccessToken, SAMPLE_CLIENT_REGISTRATION_REQUEST); // <5>
+		ClientRegistrationResponse clientRegistrationResponse =
+				registerClient(initialAccessToken, clientRegistrationRequest);	// <5>
 
-		assert (clientRegistrationResponse.clientName().contentEquals("client-1")); // <6>
+		assert (clientRegistrationResponse.clientName().contentEquals("client-1"));	// <6>
 		assert (!Objects.isNull(clientRegistrationResponse.clientSecret()));
 		assert (clientRegistrationResponse.scope().contentEquals("openid profile email"));
 		assert (clientRegistrationResponse.grantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE.getValue()));
@@ -71,12 +73,13 @@ public class DcrClient {
 		assert (!clientRegistrationResponse.registrationAccessToken().isEmpty());
 		assert (!clientRegistrationResponse.registrationClientUri().isEmpty());
 
-		String registrationAccessToken = clientRegistrationResponse.registrationAccessToken(); // <7>
+		String registrationAccessToken = clientRegistrationResponse.registrationAccessToken();	// <7>
 		String registrationClientUri = clientRegistrationResponse.registrationClientUri();
 
-		DcrResponse retrievedClient = this.retrieveClient(registrationAccessToken, registrationClientUri); // <8>
+		ClientRegistrationResponse retrievedClient = retrieveClient(registrationAccessToken, registrationClientUri);	// <8>
 
-		assert (retrievedClient.clientName().contentEquals("client-1")); // <9>
+		assert (retrievedClient.clientName().contentEquals("client-1"));	// <9>
+		assert (!Objects.isNull(retrievedClient.clientId()));
 		assert (!Objects.isNull(retrievedClient.clientSecret()));
 		assert (retrievedClient.scope().contentEquals("openid profile email"));
 		assert (retrievedClient.grantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE.getValue()));
@@ -86,26 +89,27 @@ public class DcrClient {
 		assert (!retrievedClient.registrationClientUri().isEmpty());
 	}
 
-	public DcrResponse registerClient(String initialAccessToken, DcrRequest request) { // <10>
+	public ClientRegistrationResponse registerClient(String initialAccessToken, ClientRegistrationRequest request) {	// <10>
 		return this.webClient
 				.post()
 				.uri("/connect/register")
 				.contentType(MediaType.APPLICATION_JSON)
 				.accept(MediaType.APPLICATION_JSON)
 				.header(HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(initialAccessToken))
-				.body(Mono.just(request), DcrRequest.class)
+				.body(Mono.just(request), ClientRegistrationRequest.class)
 				.retrieve()
-				.bodyToMono(DcrResponse.class)
+				.bodyToMono(ClientRegistrationResponse.class)
 				.block();
 	}
 
-	public DcrResponse retrieveClient(String registrationAccessToken, String registrationClientUri) { // <11>
+	public ClientRegistrationResponse retrieveClient(String registrationAccessToken, String registrationClientUri) {	// <11>
 		return this.webClient
 				.get()
 				.uri(registrationClientUri)
 				.header(HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(registrationAccessToken))
 				.retrieve()
-				.bodyToMono(DcrResponse.class)
+				.bodyToMono(ClientRegistrationResponse.class)
 				.block();
 	}
+
 }

+ 42 - 0
docs/src/main/java/sample/registration/SecurityConfig.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package sample.registration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
+import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
+import org.springframework.security.web.SecurityFilterChain;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+	@Bean
+	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
+		OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
+		http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
+				.oidc(oidc -> oidc.clientRegistrationEndpoint(Customizer.withDefaults()));	// <1>
+		http.oauth2ResourceServer(oauth2ResourceServer ->
+				oauth2ResourceServer.jwt(Customizer.withDefaults()));
+
+		return http.build();
+	}
+
+}

+ 16 - 13
docs/src/test/java/sample/dcr/DynamicClientRegistrationTests.java → docs/src/test/java/sample/registration/DynamicClientRegistrationTests.java

@@ -13,19 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package sample.dcr;
+package sample.registration;
 
 import com.jayway.jsonpath.JsonPath;
 import org.junit.jupiter.api.Test;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.web.server.LocalServerPort;
-import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.http.MediaType;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.web.reactive.function.client.WebClient;
 
@@ -34,9 +37,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
-
 /**
- * Tests for Dynamic Client Registration how-to guide
+ * Tests for Dynamic Client Registration how-to guide.
  *
  * @author Dmitriy Dubson
  */
@@ -54,12 +56,12 @@ public class DynamicClientRegistrationTests {
 	private String port;
 
 	@Test
-	public void dynamicallyRegisterAClient() throws Exception {
-		String tokenRequestBody = "scope=client.create&grant_type=client_credentials" ;
+	public void dynamicallyRegisterClient() throws Exception {
 		MockHttpServletResponse tokenResponse = this.mvc.perform(post("/oauth2/token")
-						.with(httpBasic("dcr-client", "secret"))
-						.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
-						.content(tokenRequestBody))
+						.with(httpBasic("registrar-client", "secret"))
+						.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
+						.param(OAuth2ParameterNames.SCOPE, "client.create")
+						.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE))
 				.andExpect(status().isOk())
 				.andExpect(jsonPath("$.access_token").isNotEmpty())
 				.andReturn()
@@ -67,15 +69,16 @@ public class DynamicClientRegistrationTests {
 
 		String initialAccessToken = JsonPath.parse(tokenResponse.getContentAsString()).read("$.access_token");
 
-		WebClient webClient = WebClient.builder().baseUrl("http://127.0.0.1:%s".formatted(port)).build();
-		DcrClient dcrClient = new DcrClient(webClient);
+		WebClient webClient = WebClient.builder().baseUrl("http://127.0.0.1:%s".formatted(this.port)).build();
+		ClientRegistrar clientRegistrar = new ClientRegistrar(webClient);
 
-		dcrClient.exampleRegistration(initialAccessToken);
+		clientRegistrar.exampleRegistration(initialAccessToken);
 	}
 
 	@EnableAutoConfiguration
 	@EnableWebSecurity
-	@Import({DcrConfiguration.class, RegisteredClientConfiguration.class})
+	@ComponentScan
 	static class AuthorizationServerConfig {
 	}
+
 }