<Spring Security> bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' cannot be found

Viewed 6040

Hi I am learning about Spring Security and was trying to create a simple OAuth2 client and resource server based on the guidelines at https://dzone.com/articles/implement-oauth-20-easily-with-spring-boot-and-spr

I came into an issue where the compiler keeps saying that it cannot find a bean for "ClientRegistrationRepository". I did some digging on the web, which says that if the Spring client configurations are configured correctly, it should work. Someone having similar issues said the problem may be caused by indetation issue in the properties file, but I am not seeing such case.

May I seek for your help to see if there is anything configured incorrectly, thanks.

Console output

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method webClient in com.somecompany.configuration.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' in your configuration.

OAuth2 client main class

package com.somecompany;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Oauth2DemoClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(Oauth2DemoClientApplication.class, args);
    }

}

OAuth2 client controller

package com.somecompany.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

@RestController
@RequestMapping("/api/client")
public class Oauth2DemoClientController {

    @Autowired
    private WebClient webClient;

    @Value("${resourceServer.url}")
    private String resourceServerUrl;

    @Value("${resourceServer.helloPath}")
    private String resourceServerHelloPath;

    @GetMapping("/")
    public String home(@AuthenticationPrincipal OidcUser user) {
        return "Welcome " + user.getFullName();
    }

    @GetMapping("/hello")
    public String sayHello() {
        return webClient.get().uri(resourceServerUrl + resourceServerHelloPath).retrieve().bodyToMono(String.class)
                .block();
    }
}

OAuth2 client configuration

package com.somecompany.configuration;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

    @Value("${defaultClientApplication}")
    private String defaultClientApplication;

    @Bean
    WebClient webClient(ClientRegistrationRepository clientRegistrations,
            OAuth2AuthorizedClientRepository authorizedClients) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        oauth2.setDefaultOAuth2AuthorizedClient(true);
        oauth2.setDefaultClientRegistrationId(defaultClientApplication);
        return WebClient.builder().apply(oauth2.oauth2Configuration()).build();
    }
}

OAuth2 client application.yml

logging.level.root: "debug"

defaultClientApplication: "okta"

spring:
  security:
    oauth2:
      client:
        provider:
          okta:
            issuer-uri: "https://dev-27548664.okta.com/oauth2/default"
        registration:
          okta:
            client-id: {client ID}
            client-secret: {client secret}
      resourceServer:
        url: "http://localhost:8081"
        helloPath: "/api/resource/hello"

OAuth2 client pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.somecompany</groupId>
    <artifactId>oauth2-demo-client</artifactId>
    <version>1.0.0</version>
    <name>oauth2-demo-client</name>
    <description>oauth2-demo-client</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
2 Answers

Issue is with your application.yml config indentation. security should be child of spring :

spring:
  security:
    oauth2:

Update:

YML properties are case sensitive. Try to change resourceServer to resourceserver

I'd suggest using the Okta Spring Boot starter. It shortens the spring.security.oauth2.* properties to be more intuitive.

okta.oauth2.issuer=<your-issuer>
okta.oauth2.client-id=<your-client-id>
okta.oauth2.client-secret=<your-client-secret>

If you want to use Spring Security, I'd recommend the following dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

Then, configure it as follows:

spring:
  security:
    oauth2:
      client:
        provider:
          okta:
            issuer-uri: <your-issuer>
        registration:
          okta:
            client-id: <your-client-id>
            client-secret: <your-client-secret>
            scope: openid,profile,email
Related