September 18, 2026

Spring Security Tutorial 5 – Using OAuth 2 Authentication

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:

Related: JPA Auditing with MySQL (often enabled in the same secured apps).

We will cover:

  1. What OAuth 2 login gives you
  2. Dependencies
  3. Register an OAuth app (Google example)
  4. application.properties / YAML
  5. SecurityFilterChain configuration
  6. Login page link
  7. Read the logged-in OAuth user
  8. 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)

  1. Open Google Cloud Console → APIs & Services → Credentials.
  2. Create an OAuth client ID (Web application).
  3. 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 users table

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 /login and /oauth2/** are permitted, and you are not requiring auth for the authorization endpoint.
  • Missing email attribute — add email scope 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 createdBy uses the OAuth email/username.

Kindson Munonye

Kindson Munonye is a software engineer and technical author covering machine learning, statistics, REST APIs, Python, and software engineering. He publishes free tutorials on The Genius Blog and live classes on Alkademy. GitHub · LinkedIn · About · Alkademy

View all posts by Kindson Munonye →
0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted