Why social login matters in 2024
Users hate creating new accounts. Every extra password field in a signup form costs you conversions. OAuth2 login with Google in Spring Boot, explained simply, is the antidote: in a few minutes of configuration, your users can sign in with a single click, and your team avoids managing password reset flows, hashing algorithms, and credential storage.
We've shipped this pattern across multiple platforms—e-commerce sites, SaaS dashboards, ride-hailing backends—and it consistently reduces friction at the entry point. By the end of this article, you'll have a production-ready implementation using Spring Security's OAuth2 support.
Register the client in Google Cloud Console
Before you write any Spring code, you need OAuth credentials from Google. This is your entry card into their OAuth2 system.
Head to the Google Cloud Console and create a new project (or use an existing one). Navigate to Credentials and create a new OAuth 2.0 Client ID. When prompted for application type, select Web application.
In the authorized redirect URIs section, add these two entries:
http://localhost:8080/login/oauth2/code/google(for local development)https://yourdomain.com/login/oauth2/code/google(for production)
This URI is critical. Google will only redirect users back to your application if the callback matches exactly. Spring Security by default listens for OAuth responses at /login/oauth2/code/{registrationId}, so the path must be /login/oauth2/code/google for a registration named google.
Once created, you'll receive a Client ID and Client Secret. Treat the secret like a password—never commit it to version control. Store both in environment variables or a secure secrets manager.
Configure Spring Security for OAuth2
With credentials in hand, the Spring side is straightforward. Add the Spring Security OAuth2 starter to your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>Then, in your application.yml, add the OAuth2 client registration:
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope:
- email
- profileSpring Security infers the provider endpoints (authorization URL, token URL) automatically for well-known providers like Google. The scopes email and profile tell Google we want the user's email address and basic profile info—enough to create a local user record.
Next, configure a minimal SecurityFilterChain:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz ->
authz
.requestMatchers("/", "/login").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 ->
oauth2.defaultSuccessUrl("/dashboard", true)
);
return http.build();
}
}
That's it. Spring Security will automatically:
- Redirect unauthenticated users to a login page with a Google button
- Handle the OAuth2 authorization code flow
- Exchange the code for tokens
- Fetch user details and create a session
- Redirect to
/dashboardon success
Link OAuth2 logins to local user records
By default, Spring Security creates an in-memory representation of the OAuth2 user, but you'll likely want to persist users in your own database so you can attach roles, preferences, and business logic.
Implement an OAuth2UserService to intercept the login flow and create or update a user record:
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
@Autowired
private UserRepository userRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest)
throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);
String email = oAuth2User.getAttribute("email");
String name = oAuth2User.getAttribute("name");
String picture = oAuth2User.getAttribute("picture");
User user = userRepository.findByEmail(email)
.orElseGet(() -> {
User newUser = new User();
newUser.setEmail(email);
newUser.setName(name);
newUser.setPicture(picture);
newUser.setCreatedAt(LocalDateTime.now());
return userRepository.save(newUser);
});
// Update picture in case it changed
user.setPicture(picture);
userRepository.save(user);
return oAuth2User;
}
}
Register this service in your security config:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private CustomOAuth2UserService customOAuth2UserService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz ->
authz
.requestMatchers("/", "/login").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 ->
oauth2
.userInfoEndpoint(userInfo ->
userInfo.oidcUserService(customOAuth2UserService)
)
.defaultSuccessUrl("/dashboard", true)
);
return http.build();
}
}
Now, on first login, a new user is created in your database. On subsequent logins, the existing user is updated. This approach lets you track login history, attach roles, and integrate OAuth2 users into your existing access control system.
Frontend integration for single-page apps
If you're running a separate frontend (React, Next.js, Vue), you'll want to use a backend-for-frontend (BFF) pattern to keep OAuth tokens out of the browser entirely.
The flow looks like this:
- User clicks "Login with Google" on the SPA
- Frontend redirects to
https://api.yourdomain.com/oauth2/authorization/google - Backend redirects to Google's authorization endpoint
- Google redirects back to backend with authorization code
- Backend exchanges code for tokens, stores them server-side (in an HTTP-only session cookie), and redirects to frontend with a session ID
- Frontend makes authenticated requests to the backend; the session cookie is sent automatically
With Spring Security's default OAuth2 setup, the session cookie is already HTTP-only. Configure it explicitly to be extra safe:
@Configuration
public class CookieConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSION");
serializer.setCookiePath("/");
serializer.setHttpOnly(true);
serializer.setSecure(true); // Only over HTTPS
serializer.setSameSite("Strict");
return serializer;
}
}
For your SPA, expose an endpoint to check authentication status:
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@GetMapping("/me")
public ResponseEntity<UserDTO> getCurrentUser(
@AuthenticationPrincipal OAuth2User principal) {
if (principal == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
String email = principal.getAttribute("email");
String name = principal.getAttribute("name");
return ResponseEntity.ok(new UserDTO(email, name));
}
@PostMapping("/logout")
public ResponseEntity<Void> logout(HttpServletRequest request,
HttpServletResponse response) throws ServletException {
request.logout();
return ResponseEntity.ok().build();
}
}
Your frontend can call GET /api/auth/me on mount to check if the user is logged in, and render accordingly.
Common mistakes
Redirect URI mismatch. If you're getting a 400 error with "redirect_uri_mismatch," double-check the exact URI in Google Cloud Console against your Spring config. Remember that localhost:8080 and 127.0.0.1:8080 are different URLs to Google.
Storing secrets in code. Never hardcode client-id or client-secret` in your repository. Always use environment variables or a secrets manager. We've seen this in production code more times than we'd like to admit.
Forgetting to persist the user. If you skip the custom OAuth2UserService`, your users won't appear in your database, and you'll lose audit trails and integration points with your business logic.
Mixing OAuth2 tokens with traditional sessions in SPAs. If your frontend stores tokens in localStorage, you're vulnerable to XSS attacks. Always use HTTP-only cookies and a BFF pattern for SPAs.
Not handling token refresh. OAuth2 access tokens expire. Spring Security handles refresh automatically when using the BFF pattern, but if you're exposing tokens to the frontend, you need to manage refresh yourself—which is error-prone.
Key takeaways
- Register OAuth2 credentials in Google Cloud Console and configure your redirect URI to match
/login/oauth2/code/googleexactly. - Use Spring Security's built-in OAuth2 support with minimal configuration—just client ID, secret, and scopes.
- Implement a custom
OAuth2UserServiceto persist OAuth2 users into your database on first login, enabling role assignment and audit trails. - For single-page apps, use a backend-for-frontend pattern to keep tokens in HTTP-only server-side session cookies, not browser storage.
- Always load credentials from environment variables, never hardcode secrets in your application.
- Test the redirect URI locally and in staging before deploying to production—mismatches will block users at login.






Comments
Loading comments…