Master OAuth2 with Spring Cloud Security: Step‑by‑Step Guide

This article introduces Spring Cloud Security and demonstrates how to integrate OAuth2 for single sign‑on, token relay, and token exchange in a Spring Boot application, covering OAuth2 concepts, authorization flows, module setup, configuration, and practical usage of authorization‑code and password grant types with code examples.

macrozheng
macrozheng
macrozheng
Master OAuth2 with Spring Cloud Security: Step‑by‑Step Guide
Spring Cloud Security provides a set of solutions for building secure Spring Boot applications; combined with OAuth2 it enables single sign‑on, token relay, token exchange, and other features.

OAuth2 Introduction

OAuth 2.0 is an industry‑standard protocol for authorization. It defines specific grant flows to simplify client development for web, desktop, and mobile applications.

OAuth2 Terminology

Resource Owner: the end user who owns the protected resource and has an account.

Resource Server: the server that hosts the protected resources and serves them when a valid access token is presented.

Client: the application that accesses resources on behalf of the user, using an access token; it can be a browser, mobile app, or server.

Authorization Server: the server that authenticates users and issues tokens to clients after successful authentication.

Four Grant Types

Authorization Code: the standard OAuth2 flow where the client redirects the user to the authorization server, obtains an authorization code, and exchanges it for an access token.

Implicit: a simplified flow that skips the authorization code step and returns an access token directly.

Resource Owner Password Credentials: the client directly collects the user's username and password and exchanges them for an access token.

Client Credentials: the client authenticates itself (e.g., with client_id and client_secret) to obtain an access token.

Two Common Grant Types

Authorization Code Grant

Authorization Code Flow Diagram
Authorization Code Flow Diagram

(A) Client redirects the user to the authorization server.

(B) User logs in and grants authorization on the authorization server.

(C) Authorization server returns an authorization code to the client.

(D) Client exchanges the authorization code (and redirect URI) for an access token.

(E) Authorization server issues the access token (optionally with a refresh token).

Password Grant

Password Grant Flow Diagram
Password Grant Flow Diagram

(A) Client collects the username and password from the user.

(B) Client sends the credentials to the authorization server.

(C) Authorization server returns an access token (optionally with a refresh token).

Using OAuth2

Creating oauth2-server Module

We create an oauth2-server module to act as the authorization server.

Add the following dependencies to pom.xml:

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

Configure application.yml:

server:
  port: 9401
spring:
  application:
    name: oauth2-service

Implement UserService that implements UserDetailsService to load user information:

@Service
public class UserService implements UserDetailsService {
    private List<User> userList;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @PostConstruct
    public void initData() {
        String password = passwordEncoder.encode("123456");
        userList = new ArrayList<>();
        userList.add(new User("macro", password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin")));
        userList.add(new User("andy", password, AuthorityUtils.commaSeparatedStringToAuthorityList("client")));
        userList.add(new User("mark", password, AuthorityUtils.commaSeparatedStringToAuthorityList("client")));
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<User> findUserList = userList.stream()
            .filter(user -> user.getUsername().equals(username))
            .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(findUserList)) {
            return findUserList.get(0);
        } else {
            throw new UsernameNotFoundException("用户名或密码错误");
        }
    }
}

Add the authorization server configuration with @EnableAuthorizationServer:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserService userService;

    // Configure password grant
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authenticationManager(authenticationManager)
                 .userDetailsService(userService);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
               .withClient("admin") // client_id
               .secret(passwordEncoder.encode("admin123456")) // client_secret
               .accessTokenValiditySeconds(3600)
               .refreshTokenValiditySeconds(864000)
               .redirectUris("http://www.baidu.com")
               .scopes("all")
               .authorizedGrantTypes("authorization_code", "password");
    }
}

Add the resource server configuration with @EnableResourceServer:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .requestMatchers()
            .antMatchers("/user/**"); // protected resource paths
    }
}

Configure Spring Security to allow authentication endpoints and form login:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin().permitAll();
    }
}

Add a test controller to verify authentication:

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/getCurrentUser")
    public Object getCurrentUser(Authentication authentication) {
        return authentication.getPrincipal();
    }
}

Authorization Code Grant Usage

Start the oauth2-server service.

In a browser, visit the authorization URL:

http://localhost:9401/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all&state=normal

Enter username and password to log in.

Login Page
Login Page

After login, grant authorization.

Authorization Prompt
Authorization Prompt

The browser redirects to the configured redirect URI with an authorization code: https://www.baidu.com/?code=eTsADY&state=normal Exchange the code for an access token by sending a POST request to http://localhost:9401/oauth/token with Basic authentication (client_id and client_secret) and the required body parameters.

Use the obtained access token in the Authorization header to call the protected endpoint http://localhost:9401/user/getCurrentUser, which now succeeds.

Successful API Call
Successful API Call

Password Grant Usage

Send a POST request to http://localhost:9401/oauth/token using Basic authentication (client_id and client_secret).

Include the username and password in the request body to obtain an access token.

Password Grant Request
Password Grant Request

Modules Used

springcloud-learning
└── oauth2-server -- OAuth2 authentication test service

Project Source Code

https://github.com/macrozheng/springcloud-learning

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaSpring BootOAuth2
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

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.