OAuth2 Login with Spring Security
OAuth2 lets users sign in with their Google, GitHub, or other accounts — no passwords to manage.
OAuth2 Flow
1. User clicks "Login with Google"
2. App redirects to Google's consent screen
3. User approves → Google redirects back with authorization code
4. App exchanges code for access token (server-side)
5. App fetches user info from Google
6. App creates/updates local user → issues JWT
Setup
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
Google OAuth2
Register at console.cloud.google.com:
- Create project → APIs & Services → Credentials
- Create OAuth 2.0 Client ID
- Authorized redirect URI:
http://localhost:8080/login/oauth2/code/google
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid, profile, email
GitHub OAuth2
Register at github.com/settings/developers:
- New OAuth App
- Callback URL:
http://localhost:8080/login/oauth2/code/github
spring:
security:
oauth2:
client:
registration:
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
scope: read:user, user:email
Security Config
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final CustomOAuth2UserService oAuth2UserService;
private final OAuth2AuthenticationSuccessHandler successHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/oauth2/**").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(info -> info.userService(oAuth2UserService))
.successHandler(successHandler)
);
return http.build();
}
}
Custom OAuth2 User Service
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
private final UserRepository userRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest request) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(request);
String provider = request.getClientRegistration().getRegistrationId(); // "google" or "github"
String email = oAuth2User.getAttribute("email");
String name = oAuth2User.getAttribute("name");
// Find or create local user
AppUser user = userRepository.findByEmail(email)
.orElseGet(() -> {
AppUser newUser = new AppUser();
newUser.setEmail(email);
newUser.setUsername(name);
newUser.setProvider(provider);
newUser.setRoles(Set.of("USER"));
return userRepository.save(newUser);
});
return oAuth2User;
}
}
Success Handler — Issue JWT After OAuth2
@Component
public class OAuth2AuthenticationSuccessHandler
extends SimpleUrlAuthenticationSuccessHandler {
private final JwtService jwtService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();
String email = oAuth2User.getAttribute("email");
// Generate JWT
String token = jwtService.generateTokenForEmail(email);
// Redirect to frontend with token
String redirectUrl = "http://localhost:3000/oauth2/callback?token=" + token;
getRedirectStrategy().sendRedirect(request, response, redirectUrl);
}
}
Key Takeaways
spring-boot-starter-oauth2-client+ YAML config = OAuth2 login.- Override
DefaultOAuth2UserServiceto create/update local users. - Issue a JWT after OAuth2 login for subsequent API calls.
- Store client secrets in environment variables, never in code.
- Common providers: Google, GitHub, Microsoft, Facebook, Okta.
What’s Next?
Next: Role-Based Access Control — @PreAuthorize, @Secured, and role hierarchies.