Implement OAuth Resource Server using Spring Security OAuth2 Resource Server

Resource Server in OAuth2 is used to protect access to resources, APIs. It will validate the access token passed by the Client Application, with the Authorization Server to decide if the Client Application has access to the resources and APIs it wants. In this tutorial, I show you how to implement OAuth Resource Server using Spring Security OAuth2 Resource Server!

First, I will create a new Spring Boot project with Spring Web, Spring Security OAuth2 Resource Server as an example:

Result:

First, I will create a new RESTful API that acts as a resource that we need the resource server to protect. The content of this API is as simple as this:

Now I will create a new class to configure Spring Security to protect for this RESTful API with the following initial content:

With the above configuration, only the logged-in user can access all application requests and the user’s login information is stored in memory or a database system.

We won’t be able to request http://localhost:8080/hello right now:

If you now need to implement the Resource Server to authenticate all requests to our application using the access token issued by the Authorization Server, you can add the following lines of code:

Resource Server will need the information of the Authorization Server so that it can check if the access token was issued by the Authorization Server? Therefore, you need to open the application.properties file to configure this Authorization Server information.

As an example for this tutorial, I will start the Authorization Server built using Spring Authorization Server in this tutorial. Then I will configure the Authorization Server information for this example as follows:

I also change the port of the example application, so as not to conflict with the port of the Authorization Server.

Please note that we need to enable OpenID Connect support for Authorization Server because Resource Server, when we configure issuer-uri as above, will validate information about OpenID Provider using URL http://localhost:8080/ .well-known/openid-configuration. You can read more here https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html#_specifying_the_authorization_server.

You can enable OpenID Connect support for our Authorization Server by adding the following code in the AuthorizationServerConfiguration class:

Now, suppose I have a RegisteredClient in the Authorization Server as follows:

Get this RegisteredClient’s access token:

and request the URL http://localhost:8081/hello again with the access token passed in the Authorization Bearer, you will see the following results:

If you notice, with the above configuration of Spring Security, all access tokens issued by the Authorization Server can access APIs. In fact, we won’t do like that.

In the access token, there is a claim named scope and we will use it to determine that with this request URL, what scope the access token must have to access it.

If you decode the RegisteredClient’s access token above, you’ll see, currently, there is no claim scope at all:

because we don’t configure a scope for this RegisteredClient.

Now, I will change the configuration of Spring Security to only accept requests with an access token whose scope is “access-hello” to access “/hello”, as follows:

We will use the hasAuthority() method with requestMachers for the “/hello” request. The parameter of the hasAuthority() method is a string that starts with SCOPE and following by the scope name that the RegisteredClient access token must have.

At this point, if you restart the example application, and request to “/hello” with the above RegisteredClient access token, you will see a 403 Forbidden error as follows:

To configure the scope for RegisteredClient in the example above, I will edit the code as follows:

As you can see, we will use the scope() method to do this.

Restart Authorization Server, get back the access token for this RegisteredClient, and then request again to “http://localhost:8081/hello”, you will see the result “Hello” is returned.

Decode access token, you will see the following result:

5/5 - (1 vote)

14 thoughts on “Implement OAuth Resource Server using Spring Security OAuth2 Resource Server

  1. Hello I cloned your git repo and getting this error

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘authorizationServerSecurityFilterChain’ defined in class path resource [com/huongdanjava/springauthorizationserver/AuthorizationServerConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method ‘authorizationServerSecurityFilterChain’ threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘jwkSource’ defined in class path resource [com/huongdanjava/springauthorizationserver/AuthorizationServerConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.nimbusds.jose.jwk.source.JWKSource]: Factory method ‘jwkSource’ threw exception; nested exception is java.io.FileNotFoundException: src\main\resources\huongdanjava.pfx (The system cannot find the path specified)

    Can you guide me?

      1. This was resolved, now I tried with the below token

        {
        “sub”: “sergey”,
        “aud”: “client1”,
        “nbf”: 1663344140,
        “scope”: [
        “read”
        ],
        “roles”: [
        “USER”
        ],
        “iss”: “http://127.0.0.1:1001”,
        “exp”: 1663344440,
        “iat”: 1663344140
        }

        and also has the bean

        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http
        .authorizeHttpRequests((authz) -> authz
        .antMatchers(“/hello”).hasAuthority(“SCOPE_access-hello”)
        .anyRequest().authenticated()
        )
        .oauth2ResourceServer().jwt();
        // @formatter:on

        return http.build();
        }
        but still able to access the URI. Ideally I should get 403

  2. These are really useful. When I try the resource server, although I have used your repo cloned directly, the resource server is saying unauthorized 403. What can the issue be?

      1. Hi Khanh Nguyen,
        I generated tokens with required scope.

        {
        “access_token”: “eyJ4NXQjUzI1NiI6ImRBcDRlU3ZhU1ZHdVlZTDVib3d2eWFuZjNtTFJOLXRkcm8taGk5UnNISUUiLCJraWQiOiJodW9uZ2RhbmphdmEiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJodW9uZ2RhbmphdmExIiwiYXVkIjoiaHVvbmdkYW5qYXZhMSIsIm5iZiI6MTY0NjkxMzEyMiwic2NvcGUiOlsiYWNjZWVzLWhlbGxvIl0sImlzcyI6Imh0dHA6XC9cL2xvY2FsaG9zdDo4MDgwIiwiZXhwIjoxNjQ2OTE0OTIyLCJpYXQiOjE2NDY5MTMxMjJ9.JDX2LCbkhXtTtmHzFnPCXtGJehwC-gKXb3HzjDTxUevU6geEn-g2PK7-h4RcG3MPgtkTUNEts73rts1mlh3HWl2mRyXuUIWFiqzl8OvuQiEMqmvBSUQZ0IPySQNfxfh3J0Qdiio-aExIwrPPnhMQ5ac-jBwNWnyjn3rOXkc4Ni3VmvMbrlYl3VDswz4fQaTUgZhivdqDLIFUrR8XRoI9YT-_8gTlBEYaVmX5_br34dsaTRlPdpx5fGO0DoidJg7451_bdQ0ygL0elGgbxhFblPv5lST0R1ylw5I3PV3oGe1lV5VHUZ3oaBNxWm4gHYIQWupGDALH4DUmyzWEYRllBQ”,
        “scope”: “accees-hello”,
        “token_type”: “Bearer”,
        “expires_in”: 1799
        }

        Still see the issue

      2. Shanthi Raghunathan

        Reply

        Figured out the issue, the resource server checks for ” .antMatchers(“/hello”).hasAuthority(“SCOPE_access-hello”)” and the Authorization server was issuing token for ” .scope(“accees-hello”)

        so corrected Authorization server to issue token for .scope(“access-hello”)

  3. Thanks for the articles. Your blog posts really helped me learning when I’m struggling to find something working. I looked at the custom oauth2 auth server implementation. It worked fine. I am able to get the auth token as well as access token. When i wanted to implemented and get resource server example working. I started to see an error regarding JwtDecoder. Below is the error msg that I am seeing here –

    Description:

    Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean of type ‘org.springframework.security.oauth2.jwt.JwtDecoder’ that could not be found.

    Action:

    Consider defining a bean of type ‘org.springframework.security.oauth2.jwt.JwtDecoder’ in your configuration.

    Can you please let me know what is that i am missing.

    1. I think i figured it out. Looks like i added an extra spring-security dependency which is looking for some beans. I removed it and it worked fine. Thanks again for your wonderful blog posts.

Add Comment