Introduction
OAuth2 is a popular authorization standard to allow third-party applications to access resources without sharing passwords. From "Login with Google" to service-to-service authentication in microservices, OAuth2 handles it all. This article shows how to integrate OAuth2 in Spring Boot 4.x.
1. OAuth2 Fundamentals
1.1 Roles in OAuth2
┌──────────────────┐
│ Resource Owner │ ← User (người dùng)
│ (End User) │
└────────┬─────────┘
│ Authorize
▼
┌──────────────────┐ ┌──────────────────┐
│ Client │────►│ Authorization │
│ (Your App) │◄────│ Server │
│ │ │ (Google, GitHub) │
└────────┬─────────┘ └──────────────────┘
│ Access Token
▼
┌──────────────────┐
│ Resource Server │ ← API chứa data
│ (API) │
└──────────────────┘
1.2 OAuth2 Flows
| Flow | Use Case |
|---|---|
| Authorization Code | Web apps, SPAs (with user interaction) |
| Client Credentials | Service-to-service (no user) |
| PKCE | Mobile apps, SPAs (replace implicit flow) |
| Device Code | Smart TV, CLI tools |
1.3 OpenID Connect (OIDC)
OIDC is a layer on top of OAuth2, adding identity layer:
- OAuth2: "Allow this app to access my Google Drive" (Authorization)
- OIDC: "Sign in with Google account" (Authentication + Authorization)
OIDC endpoints:
/.well-known/openid-configuration- ID Token (contains user information)
- UserInfo endpoint
2. OAuth2 Client — Social Login
2.1 Dependencies & Configuration
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
# application.yaml
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid, profile, email
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
scope: read:user, user:email
2.2 Security Config with OAuth2
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login", "/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.userInfoEndpoint(userInfo -> userInfo
.userService(customOAuth2UserService)
)
);
return http.build();
}
2.3 Custom OAuth2 User Service
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;
public CustomOAuth2UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest)
throws OAuth2AuthenticationException {
OAuth2User oauth2User = super.loadUser(userRequest);
String provider = userRequest.getClientRegistration().getRegistrationId();
String email = oauth2User.getAttribute("email");
String name = oauth2User.getAttribute("name");
// Tìm hoặc tạo user trong database
User user = userRepository.findByEmail(email)
.orElseGet(() -> {
User newUser = new User();
newUser.setEmail(email);
newUser.setName(name);
newUser.setProvider(provider);
newUser.setRoles(Set.of("USER"));
newUser.setEnabled(true);
return userRepository.save(newUser);
});
return new CustomOAuth2User(oauth2User, user);
}
}
3. OAuth2 Resource Server — Validate JWT
3.1 Configuration
When your application is a Resource Server (API receives JWT from client):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://accounts.google.com
# hoặc
jwk-set-uri: https://www.googleapis.com/oauth2/v3/certs
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
);
return http.build();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthorities =
new JwtGrantedAuthoritiesConverter();
grantedAuthorities.setAuthoritiesClaimName("roles");
grantedAuthorities.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(grantedAuthorities);
return converter;
}
4. Client Credentials — Service-to-Service
spring:
security:
oauth2:
client:
registration:
internal-service:
provider: custom-auth-server
client-id: ${SERVICE_CLIENT_ID}
client-secret: ${SERVICE_CLIENT_SECRET}
authorization-grant-type: client_credentials
scope: read, write
provider:
custom-auth-server:
token-uri: https://auth.example.com/oauth2/token
@Service
public class ExternalApiService {
private final RestClient restClient;
public ExternalApiService(
RestClient.Builder builder,
OAuth2AuthorizedClientManager authorizedClientManager) {
this.restClient = builder
.baseUrl("https://api.other-service.com")
.requestInterceptor(
new OAuth2ClientHttpRequestInterceptor(authorizedClientManager))
.build();
}
public List<DataResponse> fetchData() {
return restClient.get()
.uri("/api/data")
.retrieve()
.body(new ParameterizedTypeReference<>() {});
}
}
5. Combine JWT Custom + OAuth2
In fact, many applications support both:
- JWT custom: Username/password login
- OAuth2: Social login (Google, GitHub)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/oauth2/**").permitAll()
.anyRequest().authenticated()
)
// Custom JWT filter
.addFilterBefore(jwtAuthFilter,
UsernamePasswordAuthenticationFilter.class)
// OAuth2 login (social)
.oauth2Login(oauth2 -> oauth2
.successHandler(oAuth2SuccessHandler) // Generate JWT after OAuth2 login
);
return http.build();
}
Summary
- OAuth2 is an authorization standard that allows applications to access resources on behalf of users without needing a password
- Spring Boot supports OAuth2 Client (social login), Resource Server (validate JWT), and Client Credentials (service-to-service)
- OpenID Connect adds an identity layer to OAuth2, providing an ID Token containing user information
Exercises
- Configure OAuth2 login with Google: register OAuth app on Google Cloud Console, implement social login flow
- Create Resource Server to validate JWT from an Authorization Server, test with Postman/HTTPie
- Implement hybrid auth: support both username/password login (JWT custom) and Google OAuth2 login in the same application