Fading Coder

An Old Coder’s Final Dance

Home > Tech > Content

Configuring and Validating Resource IDs in Spring Security OAuth2

Tech 2

What a Resource ID Represents

In the classic Spring Security OAuth2 setup, the system is split into two roles: the Authorization Server (issues tokens) and the Resource Server (hosts protected APIs). Each Resource Server can expose a logical resource identifier (resource_id). Clients can be granted access to specific resource IDs; if a client’s token doesn’t carry the resource ID for a given Resource Server, requests to that server are rejected. If a cleint is configured without any resource IDs, the resource check is skipped and the token is considered valid for all Resource Servers.

Declaring a Resource ID on the Resource Server

Configure every Resource Server instance with a consistent resource ID. If you run multiple instances of the same microservice, they should share the same identifier.

import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;

@Configuration
@EnableResourceServer
public class ApiResourceServer extends ResourceServerConfigurerAdapter {

    private static final String ORDERS_API_ID = "orders-api";

    @Override
    public void configure(ResourceServerSecurityConfigurer security) {
        security
            .resourceId(ORDERS_API_ID)
            .stateless(true);
    }
}

Granting Resource Access on the Authorization Server

Clients must be associated with the resource IDs they’re allowed to call. With a JDBC-backed client registry (oauth_client_details), use the resource_ids column to persist a comma-separated list of IDs.

import javax.sql.DataSource;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;

@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    private final ClientDetailsService clientDetailsService;

    public AuthServerConfig(DataSource dataSource, PasswordEncoder encoder) {
        JdbcClientDetailsService jdbc = new JdbcClientDetailsService(dataSource);
        jdbc.setPasswordEncoder(encoder);
        this.clientDetailsService = jdbc;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
    }
}

If you prefer in-memory configuration for quick tests, you can also assign resource IDs directly:

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients
        .inMemory()
            .withClient("web-client")
            .secret("{noop}secret")
            .authorizedGrantTypes("password", "refresh_token")
            .scopes("read", "write")
            .resourceIds("orders-api");
}

Where the Resource ID Is Enforced

The Resource Server performs the resource check. @EnableResourceServer inserts OAuth2AuthenticationProcessingFilter into the Spring Security filter chain (ahead of FilterSecurityInterceptor). That filter extracts the token and delegates to OAuth2AuthenticationManager, which loads the OAuth2Authentication and consults client details before proceeding.

Inside OAuth2AuthenticationManager, the logic that verifies the resource ID effectively mirrors the following:

// Simplified excerpt of the resource-id check
Collection<String> allowedResources = authentication.getOAuth2Request().getResourceIds();
if (serverResourceId != null
        && allowedResources != null
        && !allowedResources.isEmpty()
        && !allowedResources.contains(serverResourceId)) {
    throw new OAuth2AccessDeniedException(
        "Invalid token does not contain resource id (" + serverResourceId + ")");
}

When a client has been authorized for resource ID "test-resource" but attempts to call a server identified as "oauth-rs", the response will be similar to:

{"error":"access_denied","error_description":"Invalid token does not contain resource id (oauth-rs)"}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.