OAuth2 is an authorization framework that allows applications to obtain limited access to user accounts on an HTTP service. Instead of using the user's password, OAuth2 uses access tokens to prove identity.
- Resource Owner - The user (you)
- Client - Your Spring Boot app
- Authorization Server - GitHub/Google
- Resource Server - GitHub/Google API
User clicks: http://localhost:8081/oauth2/authorization/github
Redirect to: https://github.com/login/oauth/authorize?
client_id=your-github-client-id&
redirect_uri=http://localhost:8081/login/oauth2/code/github&
scope=read:user,user:email&
response_type=code&
state=random-state-value
- User enters GitHub username/password
- GitHub shows consent screen: "Spring Boot Security Demo wants to access your profile"
- User clicks "Authorize"
Redirect to: http://localhost:8081/login/oauth2/code/github?
code=authorization-code-here&
state=same-random-state-value
// Spring Security automatically makes this request
POST https://github.com/login/oauth/access_token
Content-Type: application/x-www-form-urlencoded
client_id=your-github-client-id&
client_secret=your-github-client-secret&
code=authorization-code-here&
redirect_uri=http://localhost:8081/login/oauth2/code/githubGitHub Response:
{
"access_token": "gho_xxxxxxxxxxxxxxxxxxxx",
"token_type": "bearer",
"scope": "read:user,user:email"
}// Spring Security automatically makes this request
GET https://api.github.com/user
Authorization: Bearer gho_xxxxxxxxxxxxxxxxxxxxGitHub Response:
{
"id": 12345,
"login": "johndoe",
"name": "John Doe",
"email": "john@example.com",
"avatar_url": "https://avatars.githubusercontent.com/u/12345"
}// Spring Security creates OAuth2User object
OAuth2User oauth2User = new DefaultOAuth2User(
authorities,
userAttributes,
"id" // name attribute key
);
// Sets authentication in SecurityContext
Authentication auth = new OAuth2AuthenticationToken(
oauth2User,
authorities,
"github"
);
SecurityContextHolder.getContext().setAuthentication(auth);Redirect to: http://localhost:8081/dashboard
.authorizeHttpRequests(auth -> auth
// Allow OAuth2 callback endpoints
.requestMatchers("/login/oauth2/**", "/oauth2/**").permitAll()
.requestMatchers("/api/oauth2/**").authenticated()
// ... other matchers
)
.oauth2Login(oauth2 -> oauth2
.loginPage("/login") // Custom login page
.defaultSuccessUrl("/dashboard", true) // Redirect after success
.failureUrl("/login?error=true") // Redirect on failure
)# GitHub OAuth2 Configuration
spring.security.oauth2.client.registration.github.client-id=your-github-client-id
spring.security.oauth2.client.registration.github.client-secret=your-github-client-secret
spring.security.oauth2.client.registration.github.scope=read:user,user:email
# Google OAuth2 Configuration
spring.security.oauth2.client.registration.google.client-id=your-google-client-id
spring.security.oauth2.client.registration.google.client-secret=your-google-client-secret
spring.security.oauth2.client.registration.google.scope=openid,profile,emailSpring Boot Auto-Configuration:
- Spring Boot automatically creates
ClientRegistrationobjects from properties - No need for manual
OAuth2Configclass - Built-in provider configurations for GitHub, Google, Facebook, etc.
@GetMapping("/api/oauth2/user")
public ResponseEntity<?> getOAuth2User(@AuthenticationPrincipal OAuth2User principal) {
return ResponseEntity.ok(Map.of(
"name", principal.getAttribute("name"),
"email", principal.getAttribute("email"),
"provider", getProvider(principal)
));
}// In WebController.dashboard()
if (auth.getPrincipal() instanceof OAuth2User) {
OAuth2User oauth2User = (OAuth2User) auth.getPrincipal();
model.addAttribute("oauthProvider", getProvider(oauth2User));
model.addAttribute("email", oauth2User.getAttribute("email"));
model.addAttribute("avatarUrl", getAvatarUrl(oauth2User));
}Unlike JWT/API keys, OAuth2 requires sessions because:
- Access tokens are stored server-side
- User state needs to be maintained
- CSRF protection is enabled
- Multiple requests use same authentication
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))1. User submits form → Spring Security validates → Creates session
2. Subsequent requests use JSESSIONID cookie
1. User clicks OAuth2 button → Redirected to provider → Provider redirects back
2. Spring Security exchanges code for token → Fetches user info → Creates session
3. Subsequent requests use JSESSIONID cookie
- Your app never sees user's GitHub/Google password
- Reduces security risk
- Only requests specific permissions (read:user, email)
- User can revoke access anytime
- GitHub/Google handles authentication complexity
- Multi-factor authentication handled by provider
- Access tokens can expire
- Can be revoked by user or provider
| Aspect | OAuth2 | JWT | Basic Auth |
|---|---|---|---|
| Password | Never shared | Validated once | Sent every request |
| Sessions | Required | Not needed | Not needed |
| Scalability | Medium | High | High |
| User Experience | Excellent | Good | Poor |
| Setup Complexity | High | Medium | Low |
| Security | High | High | Medium |
Cause: OAuth2 callback endpoints not permitted in SecurityConfig
Solution: Add .requestMatchers("/login/oauth2/**").permitAll()
Error: invalid_client
Description: Client authentication failed
Solution: Verify client-id and client-secret in application.properties
Error: redirect_uri_mismatch
Description: The redirect_uri MUST match the registered callback URL
Solution: Set GitHub callback URL to: http://localhost:8081/login/oauth2/code/github
Redirect to: http://localhost:8081/login/oauth2/code/github?
error=access_denied&
error_description=The+user+has+denied+your+application+access
Error: insufficient_scope
Description: The request requires higher privileges than provided
Solution: Check scope configuration in application.properties
- Go to GitHub Settings → Developer settings → OAuth Apps
- Create new OAuth App with:
- Homepage URL:
http://localhost:8081 - Authorization callback URL:
http://localhost:8081/login/oauth2/code/github
- Homepage URL:
- Copy Client ID and Client Secret to application.properties
# 1. Start application
mvn spring-boot:run
# 2. Open browser
http://localhost:8081/login
# 3. Click "GitHub" button
# 4. Complete OAuth2 flow
# 5. Check dashboard for OAuth2 user info# Add to application.properties for debugging
logging.level.org.springframework.security.oauth2=DEBUG
logging.level.org.springframework.web=DEBUG# Save cookies from browser login
curl -b cookies.txt http://localhost:8081/api/oauth2/user
# Response:
{
"message": "OAuth2 - User profile",
"name": "John Doe",
"email": "john@example.com",
"provider": "github"
}- OAuth2 is authorization, not authentication - but enables authentication
- Three-legged process - User, Your App, Provider
- Access tokens replace passwords - more secure
- Sessions required - unlike stateless JWT
- Provider handles complexity - MFA, password policies, etc.
- User controls access - can revoke anytime
OAuth2 provides secure, user-friendly authentication by leveraging trusted providers like GitHub and Google, eliminating the need for users to create new accounts or share passwords with your application.