Master OAuth2 with Spring Boot: Build a Secure Authorization Server Step‑by‑Step
This article walks through the fundamentals of OAuth2.0, explains its roles and grant types, and provides a complete Spring Boot implementation of an authorization server, resource server, and test controller with code snippets and sample requests.
1. OAuth2.0 Overview
OAuth 2.0 is an open standard for delegating authorization to third‑party applications without sharing user credentials. It defines four main roles: Resource Owner, Client, Authorization Server, and Resource Server.
Roles
Resource Owner : the user who owns protected resources.
Client : the third‑party application requesting access.
Authorization Server : validates the resource owner and issues access tokens.
Resource Server : hosts the protected resources and validates tokens.
Grant Types
OAuth2 supports four grant types:
Authorization Code : typical for third‑party login.
Implicit : simplified flow for pure‑static front‑ends.
Password : client obtains token using user’s username and password (high trust).
Client Credentials : client authenticates on its own behalf.
2. Code Implementation
2.1 Authorization Server (port 8080)
Add Maven dependencies:
<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>Create MyAuthorizationConfig extending AuthorizationServerConfigurerAdapter and configure client details, token store, token services, and endpoints.
@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");
}
// tokenStore, tokenServices, authorizationCodeServices, endpoints configuration omitted for brevity
}Create SecurityConfig extending WebSecurityConfigurerAdapter to enable form login and an in‑memory user.
@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");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}2.2 Resource Server (port 8081)
Define ResourceServerConfig to validate tokens via remote check and protect resources with 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();
}
}Test controller:
@RestController
public class TestController {
@GetMapping("/test")
public String hello() {
return "hello world";
}
}3. Test Results
Authorization request:
http://localhost:8080/oauth/authorize?client_id=test&response_type=code&scope=all&redirect_uri=http://www.baidu.com. Login with admin/123456, obtain the authorization code, exchange it for an access token, and call the protected /test endpoint. The following screenshots illustrate the responses when the token is omitted and when it is supplied.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
