Full Stack • Java • System Design • Cloud • AI Engineering

OAuth2 Login with Google and GitHub in Spring Boot

Learn how to implement OAuth2 Login in Spring Boot using Google and GitHub. Understand OAuth2 flow, client registration, redirect URI, Spring Security configuration, user profile extraction, and production best practices.

Introduction

OAuth2 Login allows users to sign in using external identity providers like:

  • Google
  • GitHub
  • Facebook
  • Okta
  • Azure AD
  • Cognito

Instead of building username/password login from scratch, your application delegates authentication to a trusted provider.

Example:

User clicks "Login with Google"
        ↓
Google authenticates user
        ↓
Spring Boot receives user profile
        ↓
Application creates local session/user record

Spring Security provides built-in OAuth2 Login support through spring-boot-starter-oauth2-client. Spring Security’s OAuth2 login uses redirect URIs like /login/oauth2/code/{registrationId} by default, for example /login/oauth2/code/google.


1. What Problem Does OAuth2 Login Solve?

Traditional login requires your application to manage:

  • User registration
  • Password hashing
  • Password reset
  • Login security
  • MFA
  • Account verification
  • Credential storage

OAuth2 Login reduces this burden.

flowchart TB

Traditional["Traditional Login"]
--> Passwords["Store Passwords"]
--> Hashing["Hash Passwords"]
--> Reset["Password Reset"]
--> Risk["Credential Risk"]

OAuth2["OAuth2 Login"]
--> Provider["Google / GitHub"]
--> Profile["Receive User Profile"]
--> AppSession["Create App Session"]

2. Real-World Example

Imagine CodeWithVenu allows developers to sign in.

Instead of asking users to create a new password, allow:

Login with Google
Login with GitHub

This is useful for:

  • Developer platforms
  • SaaS applications
  • Learning platforms
  • Internal portals
  • Admin dashboards
  • Community websites

3. OAuth2 Login Flow

sequenceDiagram

participant User
participant SpringBoot
participant Provider as Google/GitHub
participant App

User->>SpringBoot: Click Login with Google/GitHub
SpringBoot->>Provider: Redirect to Authorization URL
Provider->>User: Show login/consent screen
User->>Provider: Approve access
Provider->>SpringBoot: Redirect back with authorization code
SpringBoot->>Provider: Exchange code for token
Provider-->>SpringBoot: Access token + user info
SpringBoot->>App: Create authenticated session
App-->>User: Login success

4. Important OAuth2 Terms

Term Meaning
Client Your Spring Boot application
Provider Google or GitHub
Client ID Public identifier of your app
Client Secret Secret used by backend app
Redirect URI URL provider redirects back to after login
Scope User data your app requests
Authorization Code Temporary code returned after consent
Access Token Token used to call provider APIs
mindmap
  root((OAuth2 Login))
    Client
      Spring Boot App
    Provider
      Google
      GitHub
    Credentials
      Client ID
      Client Secret
    Redirect URI
    Scope
    Authorization Code
    Access Token

5. Redirect URI

Redirect URI is very important.

After Google or GitHub authenticates the user, it redirects the browser back to your application.

Spring Security default format:

http://localhost:8080/login/oauth2/code/{registrationId}

Examples:

Google:
http://localhost:8080/login/oauth2/code/google

GitHub:
http://localhost:8080/login/oauth2/code/github

Google’s OAuth documentation explains that redirect URIs are application endpoints where the OAuth server sends responses after user authentication. GitHub OAuth Apps also require an authorization callback URL.


6. Project Structure

oauth2-login-demo
└── src
    └── main
        └── java
            └── com.codewithvenu.oauth2
                ├── config
                │   └── SecurityConfig.java
                ├── controller
                │   └── HomeController.java
                ├── service
                │   └── OAuth2UserService.java
                └── OAuth2LoginDemoApplication.java

7. Maven Dependencies

<dependencies>

    <!-- Spring Web for REST endpoints and controller pages -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Security core -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <!-- OAuth2 Client support -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>

</dependencies>

Dependency Explanation

spring-boot-starter-web

Used to create controllers and REST endpoints.

spring-boot-starter-security

Adds Spring Security filter chain.

spring-boot-starter-oauth2-client

Adds OAuth2 client and OAuth2 Login support.


8. Create Google OAuth Client

Step-by-Step

  1. Go to Google Cloud Console
  2. Create or select a project
  3. Configure OAuth consent screen
  4. Create OAuth Client ID
  5. Choose Web Application
  6. Add authorized redirect URI:
http://localhost:8080/login/oauth2/code/google
  1. Copy Client ID
  2. Copy Client Secret
flowchart TB

A["Google Cloud Console"]
--> B["Create Project"]
--> C["OAuth Consent Screen"]
--> D["Create OAuth Client"]
--> E["Add Redirect URI"]
--> F["Copy Client ID and Secret"]

9. Create GitHub OAuth App

Step-by-Step

  1. Go to GitHub Developer Settings
  2. Create OAuth App
  3. Add Application Name
  4. Add Homepage URL:
http://localhost:8080
  1. Add Authorization Callback URL:
http://localhost:8080/login/oauth2/code/github
  1. Copy Client ID
  2. Generate and copy Client Secret
flowchart TB

A["GitHub Developer Settings"]
--> B["Create OAuth App"]
--> C["Set Homepage URL"]
--> D["Set Callback URL"]
--> E["Copy Client ID"]
--> F["Generate Client Secret"]

GitHub’s OAuth App documentation notes that OAuth Apps use an Authorization callback URL and OAuth Apps cannot have multiple callback URLs.


10. application.yml

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: ${GOOGLE_CLIENT_ID}
            client-secret: ${GOOGLE_CLIENT_SECRET}
            scope:
              - openid
              - profile
              - email

          github:
            client-id: ${GITHUB_CLIENT_ID}
            client-secret: ${GITHUB_CLIENT_SECRET}
            scope:
              - read:user
              - user:email

Explanation

registration

Defines OAuth2 clients.

google

Google registration ID.

github

GitHub registration ID.

client-id

Public application identifier.

client-secret

Secret value for backend authentication.

scope

Defines what user information your app requests.

Do not hardcode client secrets in GitHub.

Use environment variables.


11. Environment Variables

For Mac/Linux:

export GOOGLE_CLIENT_ID="your-google-client-id"
export GOOGLE_CLIENT_SECRET="your-google-client-secret"

export GITHUB_CLIENT_ID="your-github-client-id"
export GITHUB_CLIENT_SECRET="your-github-client-secret"

For Windows PowerShell:

$env:GOOGLE_CLIENT_ID="your-google-client-id"
$env:GOOGLE_CLIENT_SECRET="your-google-client-secret"

$env:GITHUB_CLIENT_ID="your-github-client-id"
$env:GITHUB_CLIENT_SECRET="your-github-client-secret"

12. Spring Security Configuration

package com.codewithvenu.oauth2.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http)
            throws Exception {

        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2Login(oauth2 -> oauth2
                .defaultSuccessUrl("/dashboard", true)
            )
            .logout(logout -> logout
                .logoutSuccessUrl("/")
                .permitAll()
            );

        return http.build();
    }
}

Code Explanation

authorizeHttpRequests

Defines which URLs are public and which require login.

requestMatchers("/", "/public/**").permitAll()

Home page and public URLs do not require login.

anyRequest().authenticated()

All other endpoints require authenticated user.

oauth2Login

Enables OAuth2 login.

defaultSuccessUrl("/dashboard", true)

After successful OAuth2 login, user is redirected to /dashboard.

logoutSuccessUrl("/")

After logout, user is redirected to home page.


13. OAuth2 Login Architecture in Spring Security

flowchart TB

Browser["Browser"]
--> SecurityFilterChain["SecurityFilterChain"]

SecurityFilterChain --> OAuth2AuthorizationRequestRedirectFilter["OAuth2 Authorization Redirect Filter"]

OAuth2AuthorizationRequestRedirectFilter --> Provider["Google / GitHub"]

Provider --> OAuth2LoginAuthenticationFilter["OAuth2 Login Authentication Filter"]

OAuth2LoginAuthenticationFilter --> UserInfoEndpoint["UserInfo Endpoint"]

UserInfoEndpoint --> SecurityContext["SecurityContext"]

SecurityContext --> Controller["Controller"]

14. Create HomeController

package com.codewithvenu.oauth2.controller;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
public class HomeController {

    @GetMapping("/")
    public String home() {
        return """
                Welcome to CodeWithVenu OAuth2 Login Demo.

                Login URLs:
                /oauth2/authorization/google
                /oauth2/authorization/github
                """;
    }

    @GetMapping("/dashboard")
    public Map<String, Object> dashboard(
            @AuthenticationPrincipal OAuth2User principal) {

        return principal.getAttributes();
    }

    @GetMapping("/me")
    public Map<String, Object> me(
            @AuthenticationPrincipal OAuth2User principal) {

        return Map.of(
                "name", principal.getAttribute("name"),
                "email", principal.getAttribute("email"),
                "attributes", principal.getAttributes()
        );
    }
}

Code Explanation

@AuthenticationPrincipal

Injects logged-in OAuth2 user.

OAuth2User

Represents authenticated user returned by provider.

principal.getAttributes()

Returns provider user profile data.

For Google, attributes usually include name, email, picture, and subject.

For GitHub, attributes may include login, id, avatar_url, and name.


15. Login URLs

Spring Security automatically creates OAuth2 authorization URLs.

Google login:

http://localhost:8080/oauth2/authorization/google

GitHub login:

http://localhost:8080/oauth2/authorization/github
flowchart LR

User["User"]
--> GoogleLogin["/oauth2/authorization/google"]
--> Google["Google Login"]

User --> GitHubLogin["/oauth2/authorization/github"]
--> GitHub["GitHub Login"]

16. Test Google Login

Start application:

mvn spring-boot:run

Open browser:

http://localhost:8080/oauth2/authorization/google

Flow:

  1. Browser redirects to Google
  2. Login using Google account
  3. Approve consent
  4. Google redirects back to Spring Boot
  5. Application redirects to /dashboard

17. Test GitHub Login

Open browser:

http://localhost:8080/oauth2/authorization/github

Flow:

  1. Browser redirects to GitHub
  2. Login using GitHub account
  3. Authorize application
  4. GitHub redirects back to Spring Boot
  5. Application redirects to /dashboard

18. OAuth2 User Data Flow

sequenceDiagram

participant User
participant App
participant Provider
participant UserInfo

User->>App: Login with Provider
App->>Provider: Redirect authorization request
Provider-->>App: Authorization code
App->>Provider: Exchange code for token
Provider-->>App: Access token
App->>UserInfo: Request user profile
UserInfo-->>App: User attributes
App-->>User: Dashboard

19. Custom OAuth2 Success Handler

Sometimes you want to run custom logic after login.

Use cases:

  • Save user to database
  • Create local user account
  • Generate JWT
  • Redirect to frontend app
  • Audit login event
package com.codewithvenu.oauth2.config;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class OAuth2LoginSuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication)
            throws IOException, ServletException {

        OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal();

        String name = oauth2User.getAttribute("name");
        String email = oauth2User.getAttribute("email");

        System.out.println("OAuth2 login success: " + name + " - " + email);

        response.sendRedirect("/dashboard");
    }
}

Update security config:

.oauth2Login(oauth2 -> oauth2
    .successHandler(oAuth2LoginSuccessHandler)
)

20. Saving OAuth2 User to Database

In real applications, after OAuth2 login, store or update the user.

flowchart TB

OAuth2Login["OAuth2 Login Success"]
--> ExtractProfile["Extract Profile"]
--> CheckUser["Check User Exists"]
--> SaveOrUpdate["Save / Update User"]
--> CreateSession["Create App Session"]

Example entity:

@Entity
@Table(name = "oauth_users")
public class OAuthUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String provider;

    private String providerId;

    private String name;

    private String email;

    private String pictureUrl;
}

Example provider values:

google
github

21. Google vs GitHub User Attributes

Attribute Google GitHub
Unique ID sub id
Name name name
Email email email may be null
Picture picture avatar_url
Username usually email login

GitHub email can be missing depending on user privacy settings and scopes.

So do not assume GitHub always returns email.


22. OAuth2 Login with Frontend App

If your frontend is React/Angular/Next.js, common production flow:

sequenceDiagram

participant Frontend
participant Backend
participant Provider
participant DB

Frontend->>Backend: Start OAuth2 login
Backend->>Provider: Redirect
Provider-->>Backend: Authorization code
Backend->>Provider: Exchange token
Backend->>DB: Save/update user
Backend-->>Frontend: Redirect with app session or JWT

For SPA/mobile apps, many teams generate their own application JWT after successful OAuth2 login.


23. Common Redirect URI Problems

Problem Cause
redirect_uri_mismatch URI in provider console does not match Spring Boot callback
404 after provider login Wrong callback URL
Invalid client Wrong client ID
Unauthorized client OAuth app not configured correctly
Missing email Scope/provider privacy settings

Correct local redirect URIs:

http://localhost:8080/login/oauth2/code/google
http://localhost:8080/login/oauth2/code/github

24. Production Configuration

For production, use real domain:

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            redirect-uri: "https://api.codewithvenu.com/login/oauth2/code/google"

Also update provider console with:

https://api.codewithvenu.com/login/oauth2/code/google
https://api.codewithvenu.com/login/oauth2/code/github

25. Security Best Practices

  • Never commit client secrets to GitHub
  • Use environment variables or secrets manager
  • Use HTTPS in production
  • Validate redirect URIs
  • Request minimum scopes
  • Do not store provider access tokens unless needed
  • Encrypt sensitive tokens if stored
  • Log login events, not tokens
  • Handle missing email carefully
  • Use CSRF protection for browser session apps
  • Use short-lived sessions
  • Review OAuth consent screen settings

26. Common Mistakes

Mistake Problem
Hardcoding client secret Secret leakage
Wrong redirect URI Login failure
Requesting too many scopes User trust issue
Assuming GitHub email exists Null pointer bugs
Storing access token in logs Token leakage
No HTTPS Token interception
Mixing session and JWT poorly Security confusion

27. Interview Questions

Q1. What is OAuth2 Login?

OAuth2 Login allows users to authenticate using external identity providers such as Google or GitHub.

Q2. What is Client ID?

Client ID identifies your application to the OAuth2 provider.

Q3. What is Client Secret?

Client Secret is a confidential value used by backend applications.

Q4. What is Redirect URI?

Redirect URI is where the provider sends the user after authentication.

Q5. What is Scope?

Scope defines what user data or permissions the application requests.

Q6. What is Authorization Code?

Authorization Code is a temporary code returned by provider and exchanged for tokens.

Q7. What Spring Boot dependency is required?

spring-boot-starter-oauth2-client.

Q8. What is the default Spring Security login URL for Google?

/oauth2/authorization/google.

Q9. What is the default callback URI pattern?

/login/oauth2/code/{registrationId}.


28. Key Takeaways

  • OAuth2 Login delegates authentication to trusted providers.
  • Spring Security supports OAuth2 Login out of the box.
  • Google and GitHub require OAuth client configuration.
  • Redirect URI must match provider settings.
  • Spring Boot uses /login/oauth2/code/{registrationId} as callback pattern.
  • Use environment variables for client secrets.
  • OAuth2 user profile can be accessed using @AuthenticationPrincipal OAuth2User.
  • In production, save/update user after successful login.
  • Use HTTPS and request minimum scopes.

Next Article

➡️ OpenID Connect with Spring Security