Wiring Sign in with Google into Spring Boot
From an empty project to a working login.
Open this lesson in the learning hubKey points
- Add
spring-boot-starter-oauth2-clientand a registration underspring.security.oauth2.client.registration.google. Spring already knows Google endpoints, so no URLs are needed. - Enable
oauth2Login()on the filter chain. That alone gives you a login page, the redirect, the code exchange, state and nonce validation, and a populated principal. - The redirect URI Spring uses by default is
/login/oauth2/code/google. It must be registered in the Google console exactly, including scheme and port. - The user arrives as an
OidcUser. Read identity fromgetSubject()- the stablesub- and never from the email, which can change. - Use a
OAuth2UserServiceto map the Google user onto your own account record on first login, so authorisation uses your roles rather than Google claims. - Behind a proxy, set
server.forward-headers-strategy=frameworkor the redirect will be built with the internal host and fail the exact-match check.
Example
# build.gradle
# implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: openid,profile,email
# Provider details are built in - no URLs needed for Google.
# Behind a reverse proxy, or the redirect_uri is built wrong:
server:
forward-headers-strategy: framework
---
@Configuration
@EnableWebSecurity
class GoogleLoginConfig {
@Bean
SecurityFilterChain web(HttpSecurity http, OAuth2UserService<OidcUserRequest,
OidcUser> users) throws Exception {
return http
.authorizeHttpRequests(a -> a
.requestMatchers("/", "/error", "/webjars/**").permitAll()
.anyRequest().authenticated())
.oauth2Login(o -> o
.userInfoEndpoint(u -> u.oidcUserService(users))
.defaultSuccessUrl("/dashboard", true))
.logout(l -> l.logoutSuccessUrl("/").invalidateHttpSession(true))
.build();
}
}
// Map the Google identity onto YOUR account on first login.
@Service
class GoogleUserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
private final OidcUserService delegate = new OidcUserService();
private final AccountRepository accounts;
GoogleUserService(AccountRepository accounts) { this.accounts = accounts; }
@Override
public OidcUser loadUser(OidcUserRequest request) {
OidcUser google = delegate.loadUser(request);
if (!Boolean.TRUE.equals(google.getEmailVerified())) {
throw new OAuth2AuthenticationException("Email not verified");
}
// sub is STABLE. Email is not - people change it.
Account account = accounts.findByGoogleSub(google.getSubject())
.orElseGet(() -> accounts.save(Account.fromGoogle(google)));
// Authorities come from YOUR roles, not from Google.
return new DefaultOidcUser(account.authorities(),
google.getIdToken(), google.getUserInfo(), "sub");
}
}
oauth2Login gives you the whole flow - your job is mapping the stable sub onto your own account and using your own roles.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the OAuth with Google course, and every lesson in it is listed on the OAuth with Google contents page.