Updated August 2026 — OAuth 2 tutorial restored for this URL.
In this tutorial we will see how to allow login to our application using OAuth 2.0 / OpenID Connect (for example Google), on top of Spring Security.
Previously we covered:
- Part 1: Introduction to Spring Security — practical login
- Part 2: Storing username and password in MySQL
Related: JPA Auditing with MySQL (often enabled in the same secured apps).
We will cover:
- What OAuth 2 login gives you
- Dependencies
- Register an OAuth app (Google example)
- application.properties / YAML
- SecurityFilterChain configuration
- Login page link
- Read the logged-in OAuth user
- Combine with form login (optional)
1. What OAuth 2 login gives you
Instead of only a local username/password form, users can sign in with an external Identity Provider (IdP). Spring Security’s OAuth2 Login support handles the redirect, authorization code exchange, and builds an authenticated OAuth2User.
2. Dependencies
In pom.xml (Spring Boot 3.x shown with Jakarta):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3. Register an OAuth app (Google example)
- Open Google Cloud Console → APIs & Services → Credentials.
- Create an OAuth client ID (Web application).
- Authorized redirect URI (Spring Boot default):
http://localhost:8080/login/oauth2/code/google
Copy the Client ID and Client secret.
4. application.properties
spring.security.oauth2.client.registration.google.client-id=YOUR_CLIENT_ID
spring.security.oauth2.client.registration.google.client-secret=YOUR_CLIENT_SECRET
spring.security.oauth2.client.registration.google.scope=openid,profile,email
For GitHub, use registration.github and redirect /login/oauth2/code/github. Provider details are auto-configured for common IdPs.
5. SecurityFilterChain configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login", "/css/**").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth -> oauth
.loginPage("/login")
)
.logout(logout -> logout
.logoutSuccessUrl("/")
);
return http.build();
}
}
Visiting a protected URL redirects unauthenticated users to your login page (or directly to the provider if you omit a custom login page).
6. Login page link
templates/login.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h1>Login</h1>
<p><a th:href="@{/oauth2/authorization/google}">Continue with Google</a></p>
</body>
</html>
The path /oauth2/authorization/{registrationId} starts the OAuth dance (google matches the registration id in properties).
7. Read the logged-in OAuth user
@GetMapping("/me")
@ResponseBody
public Map<String, Object> me(@AuthenticationPrincipal OAuth2User user) {
return Map.of(
"name", user.getAttribute("name"),
"email", user.getAttribute("email")
);
}
Attribute names depend on the provider (Google uses email, name, sub, …).
8. Combine with form login (optional)
You can keep MySQL form login from Part 2 and OAuth:
http
.authorizeHttpRequests(...)
.formLogin(form -> form.loginPage("/login").permitAll())
.oauth2Login(oauth -> oauth.loginPage("/login"));
On the same login page, show both the username/password form and the “Continue with Google” link.
For production:
- Use HTTPS and real redirect URIs
- Store secrets outside source control
- Decide whether OAuth users are auto-provisioned into your MySQL
userstable
Troubleshooting
- redirect_uri_mismatch — the console redirect URI must match exactly, including port and
/login/oauth2/code/google. - Invalid client — wrong client id/secret, or secret not refreshed after reset.
- Loop on /login — ensure
/loginand/oauth2/**are permitted, and you are not requiring auth for the authorization endpoint. - Missing email attribute — add
emailscope and enable the email claim in the provider console.
Next steps
- Revisit Part 1 and Part 2.
- Add roles/authorities after OAuth login for API authorization.
- Enable JPA Auditing so
createdByuses the OAuth email/username.