Backend Development 10 min read

Implementing OAuth2.0 Authentication and Resource Server with Spring Boot

This article explains the fundamentals of OAuth2.0, outlines its roles and grant types, and provides a step‑by‑step Spring Boot implementation—including authorization server, security configuration, resource server, and a test controller—followed by detailed testing procedures and results.

Top Architecture Tech Stack
Top Architecture Tech Stack
Top Architecture Tech Stack
Implementing OAuth2.0 Authentication and Resource Server with Spring Boot

OAuth 2.0 (Open Authorization) is an open standard that enables third‑party applications to obtain limited access to a user's protected resources without sharing credentials, and it is widely used for secure delegation in authentication and authorization scenarios.

The core roles in OAuth2.0 are the Resource Owner (the user), the Client (the third‑party app), the Authorization Server (issues tokens after authenticating the user), and the Resource Server (hosts the protected resources).

Four main grant types are supported: Authorization Code (commonly used for third‑party logins), Implicit (simplified flow for browser‑only apps), Password (direct user‑password exchange, suitable when the client is highly trusted), and Client Credentials (client‑only access). An additional refresh token grant allows token renewal.

**Code setup**

1. Add Maven dependencies for Spring Boot Web, Spring Cloud Security, and Spring Cloud OAuth2:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-security</artifactId>
        <version>2.2.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
        <version>2.2.5.RELEASE</version>
    </dependency>
</dependencies>

2. **Authorization Server configuration** (`MyAuthorizationConfig`): enables the authorization server, defines client details (in‑memory client "test" with secret "123456"), token store, token services, and supported grant types.

@Configuration
@EnableAuthorizationServer
public class MyAuthorizationConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
                .allowFormAuthenticationForClients();
    }
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("test")
                .secret(new BCryptPasswordEncoder().encode("123456"))
                .resourceIds("order")
                .authorizedGrantTypes("authorization_code","password","client_credentials","implicit","refresh_token")
                .scopes("all")
                .autoApprove(false)
                .redirectUris("http://www.baidu.com");
    }
    @Bean
    public TokenStore tokenStore() { return new InMemoryTokenStore(); }
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(clientDetailsService);
        services.setSupportRefreshToken(true);
        services.setTokenStore(tokenStore());
        services.setAccessTokenValiditySeconds(60*60*2);
        services.setRefreshTokenValiditySeconds(60*60*24*3);
        return services;
    }
    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authorizationCodeServices(authorizationCodeServices())
                 .authenticationManager(authenticationManager)
                 .tokenServices(tokenServices())
                 .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }
}

3. **Security configuration** (`SecurityConfig`): sets up password encoding, form‑login, and an in‑memory user "admin" with password "123456".

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().authenticated()
            .and().formLogin().loginProcessingUrl("/login").permitAll()
            .and().csrf().disable();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin")
            .password(new BCryptPasswordEncoder().encode("123456"))
            .roles("admin");
    }
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

4. **Resource Server configuration** (`ResourceServerConfig`): validates tokens via the authorization server’s `/oauth/check_token` endpoint and protects all endpoints with the scope "all".

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Bean
    public RemoteTokenServices tokenServices() {
        RemoteTokenServices services = new RemoteTokenServices();
        services.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
        services.setClientId("test");
        services.setClientSecret("123456");
        return services;
    }
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId("order").tokenServices(tokenServices());
    }
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/**").access("#oauth2.hasScope('all')")
            .anyRequest().authenticated();
    }
}

5. **Test controller** provides a simple endpoint returning "hello world":

@RestController
public class TestController {
    @GetMapping("/test")
    public String hello() { return "hello world"; }
}

**Testing steps and results**

Open the authorization URL: http://localhost:8080/oauth/authorize?client_id=test&response_type=code&scope=all&redirect_uri=http://www.baidu.com

Log in with username admin and password 123456 to obtain an authorization code.

Exchange the code for an access token (screenshots in the original article illustrate the token response).

Access the protected resource at http://localhost:8081/test with the token; the article shows both the failure without a token and the successful response when the token is supplied.

Images in the original post demonstrate the UI of each step (authorization page, token response, and resource access).

Author: 山河亦问安 – source: CSDN blog .

Javabackend developmentSpring BootSecurityAuthenticationREST APIOAuth2.0
Top Architecture Tech Stack
Written by

Top Architecture Tech Stack

Sharing Java and Python tech insights, with occasional practical development tool tips.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.