Welcome to the second lesson of the "OAuth Fundamentals & Mock Implementation" course! In this lesson, we'll focus on creating a mock Google OAuth implementation. This approach allows us to simulate real-world OAuth interactions in a controlled environment, reinforcing your understanding of OAuth processes without needing actual third-party services. By the end of this lesson, you'll be equipped to create a mock OAuth flow, enhancing your grasp of how OAuth—an authorization framework—can be leveraged for authentication purposes. Let's get started! 🚀
🔒 Security Note for This Unit:
In this lesson, we're implementing a simplified OAuth flow to focus on understanding the core concepts. We'll use basic patterns like /success routes and tokens in URLs. In Unit 4, we'll upgrade to production-ready security with CSRF protection (state parameters). For now, focus on understanding how OAuth connects the pieces together.
⚠️ CRITICAL SECURITY WARNING - Tokens in URL Parameters:
Our current implementation passes tokens like /?token=xxx in URL query parameters. This is unsafe for production:
- ❌ Tokens appear in browser history
- ❌ Tokens leak through server logs
- ❌ Tokens exposed via HTTP Referer headers
- ❌ Tokens can be bookmarked and shared
Production solutions:
- ✅ Use HttpOnly, Secure, SameSite cookies (recommended approach)
- ✅ Use Authorization Code + PKCE flow with proper token handling
- ✅ Never use query parameters for sensitive tokens in real applications
We use query parameters in this demo for educational clarity only. In production OAuth implementations, you should always use secure cookie-based session management or proper token storage mechanisms. This course focuses on understanding OAuth flow mechanics; implementing production-grade token delivery is covered in advanced security courses.
In a mock Google OAuth implementation, we simulate the process of authenticating users through Google without actually connecting to Google's servers. This is useful for learning and testing purposes, as it allows us to understand the OAuth flow without the complexity of real-world integrations.
We implement a basic mock Google OAuth provider using pre-built HTML templates to focus on the OAuth authorization code flow logic. The mock implementation involves template loading, OAuth route structure, and JWT token integration with OAuth-authenticated users.
The first step is loading and serving OAuth consent screens. We use pre-built HTML templates that simulate the Google OAuth interface:
Understanding resource loading:
The classpath is where Java looks for classes and resources at runtime. In Spring Boot, src/main/resources is automatically part of the classpath.
Why use ClassPathResource? It works consistently whether your app runs from an IDE, JAR file, or Docker container—regular File I/O fails when resources are packaged inside JARs. ClassPathResource handles these deployment scenarios automatically and avoids hardcoding filesystem paths.
This code loads HTML templates from the classpath. By using a separate template file, we keep the OAuth logic clean and focused, while the HTML handles the user interface. FileCopyUtils.copyToString() reads the entire file into a String for serving.
OAuth implementations follow a standard route pattern for handling the authorization flow:
This structure provides two essential endpoints:
/api/oauth/google- Serves the consent screen template./api/oauth/google/success- Handles the OAuth callback after user consent.
The clean route structure keeps the focus on OAuth flow logic rather than HTML details. We use Spring's @GetMapping annotation to define route handlers and specify MediaType.TEXT_HTML_VALUE to indicate we're returning HTML content directly to the user's browser.
The OAuth authorization code flow follows these steps in our mock implementation:
- User visits
/api/oauth/google. The consent screen is displayed. - User grants permission. The template form submits to
/api/oauth/google/success. - Server processes callback. The user is created/found and a token is generated.
- User is redirected. Back to the application with the authentication token.
Important Security Note: In production OAuth implementations, you must include a state parameter to protect against CSRF attacks. This parameter should be:
- Generated randomly when displaying the consent screen
- Stored temporarily (e.g., in session or Redis)
- Validated when processing the callback
- Removed after successful validation
We're omitting state validation in this mock implementation to keep the focus on understanding the basic OAuth flow, but never skip this in real applications—it's a critical security requirement.
The callback handler processes the OAuth response with mock data:
OAuth users are handled differently than regular users since they authenticate through external providers:
Key aspects of OAuth user creation:
- No password required. OAuth users authenticate through Google.
- User lookup. Check if the user already exists before creating.
- Simple user data. The mock implementation uses basic user information.
Understanding the code pattern:
Lambda expressions (() -> { ... }) are short anonymous functions in Java. The () -> syntax means "take no parameters and execute this code block." It's a concise way to write inline functions without declaring separate methods.
Why orElseGet() vs orElse()? The method orElseGet() only executes the lambda if the user doesn't exist—it's lazy. Using orElse() would always create the user object even if not needed, wasting resources. Always prefer orElseGet() for expensive operations like database saves.
What does "atomically" mean? Actually, this operation isn't atomic—there's a race condition where two requests could create duplicate users simultaneously. We use it here for simplicity in a mock implementation. Production code would need unique database constraints or transaction locking to prevent duplicates.
Spring Data JPA's returns an , which either contains a user or is empty. The method provides a fallback that creates and saves a new user only when needed.
After successful OAuth authentication, we generate a JWT token for the user session:
This integration:
- Uses existing JWT system. The same token generation as regular authentication.
- Includes user ID. Links the token to the authenticated user.
- Adds expiration claim. Tokens expire after 24 hours for security.
- Uses environment-based secret. JwtUtil loads secret from application properties.
The JwtUtil class encapsulates JWT operations, providing generateTokenWithUserId() to create tokens with proper expiration. Spring's ResponseEntity with HttpStatus.FOUND (302) creates a redirect response.
Why we use JwtUtil with injected configuration instead of constants:
- Secrets should never be hard-coded in source code
- Application properties allow different secrets per environment (dev/staging/production)
- Supports secret rotation without code changes
- Follows Spring Boot's externalized configuration pattern
Here's the complete OAuth controller implementation:
To test the complete OAuth flow:
- Navigate to
/api/oauth/google. See the consent screen. - Click the authorization button. The form submits to
/api/oauth/google/success. - User is created/found. Database interaction occurs.
- JWT token is generated. The user session is established.
- Redirect to main app. The user is authenticated with the token.
The HTML template handles the user interface, while your controller logic manages the authentication flow.
In this lesson, we explored how to create a mock Google OAuth implementation focusing on the core OAuth authorization code flow logic. We learned about template loading with Spring's ClassPathResource, OAuth route structure with @GetMapping, user creation for OAuth users with Spring Data JPA, and JWT token integration with proper expiration.
Important security reminders:
- Tokens in URL parameters are unsafe - we'll discuss secure patterns in Unit 5
- Always use externalized configuration (application.properties) not hard-coded values
- JWT tokens should always include expiration claims to prevent replay attacks
You now understand how these components work together to create a complete OAuth flow in Spring Boot. As you move on to the practice exercises, you'll implement these concepts and reinforce your understanding by building the OAuth routes yourself. Keep up the great work! 🌟
