Understand OAuth2 flows, implement Google sign-in, and use Spring Security's OAuth2 resource server.
Published March 5, 2025
OAuth2 is an authorization framework that lets a third-party application access user resources on another service without exposing the user's credentials.
1. User clicks "Sign in with Google"
2. Browser redirects to Google's authorization endpoint
3. User grants permission on Google
4. Google redirects back with an authorization code
5. Your server exchanges the code for access_token + id_token
6. Your server validates the token and creates a session
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
# application.yml
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid,email,profile
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login").permitAll()
.anyRequest().authenticated())
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.successHandler(oAuth2SuccessHandler()) // custom handler
.userInfoEndpoint(ui ->
ui.userService(customOAuth2UserService())) // enrich user
)
.build();
}
}
@Service
@RequiredArgsConstructor
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest request) {
OAuth2User oauthUser = super.loadUser(request);
String email = oauthUser.getAttribute("email");
String name = oauthUser.getAttribute("name");
String provider = request.getClientRegistration().getRegistrationId();
// Upsert user in our DB
User user = userRepository.findByEmail(email)
.orElseGet(() -> new User(email, name, provider));
user.setLastLoginAt(Instant.now());
userRepository.save(user);
return oauthUser;
}
}
For APIs secured by an Authorization Server (Keycloak, Auth0):
<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
# or: jwk-set-uri: https://accounts.google.com/.well-known/openid-configuration
http.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
// Spring auto-validates token signature, expiry, and issuer
| Term | Meaning |
|---|---|
| access_token | Short-lived credential to access resources |
| refresh_token | Long-lived token to get new access_tokens |
| id_token | OpenID Connect: JWT about the user |
| scope | What permissions were granted |
| PKCE | Proof Key for Code Exchange — prevents code interception |
id_token).localStorage — use httpOnly cookies or the Backend for Frontend (BFF) pattern.