Add to application.properties:
logging.level.org.springframework.security.oauth2=TRACE
logging.level.org.springframework.security.web=DEBUG
logging.level.org.springframework.web.client.RestTemplate=DEBUG
logging.level.org.springframework.http=DEBUG// Spring Security Internal Classes (Add to IDE breakpoints)
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal()
org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver.resolve()- Authorization URL generation
- Client ID and redirect URI
- State parameter generation
- Scope configuration
// In OAuth2AuthorizationRequestRedirectFilter
OAuth2AuthorizationRequest authorizationRequest
String authorizationRequestUri
ClientRegistration clientRegistration// Spring Security Internal Classes
org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication()
org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider.authenticate()- Authorization code extraction
- State parameter validation
- Token exchange preparation
// In OAuth2LoginAuthenticationFilter
String code = request.getParameter("code")
String state = request.getParameter("state")
OAuth2AuthorizationRequest authorizationRequest// Spring Security Internal Classes
org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient.getTokenResponse()
org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler.handleError()- HTTP request to GitHub token endpoint
- Client authentication (client_id, client_secret)
- Token response parsing
// In DefaultAuthorizationCodeTokenResponseClient
OAuth2AuthorizationCodeGrantRequest tokenRequest
RequestEntity<?> request // HTTP request to GitHub
ResponseEntity<OAuth2AccessTokenResponse> response// Debug the actual HTTP request
POST https://github.com/login/oauth/access_token
Headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
Body: {
"grant_type": "authorization_code",
"code": "authorization_code_here",
"redirect_uri": "http://localhost:8081/login/oauth2/code/github",
"client_id": "your_client_id",
"client_secret": "your_client_secret"
}// Spring Security Internal Classes
org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService.loadUser()
org.springframework.security.oauth2.client.userinfo.OAuth2UserRequestEntityConverter.convert()- Access token usage
- User info API call to GitHub
- User attributes mapping
// In DefaultOAuth2UserService
OAuth2UserRequest userRequest
OAuth2AccessToken accessToken
RequestEntity<?> request // HTTP request to GitHub user API
Map<String, Object> userAttributes// Debug the user info request
GET https://api.github.com/user
Headers: {
"Authorization": "Bearer gho_xxxxxxxxxxxxxxxxxxxx",
"Accept": "application/json"
}// Spring Security Internal Classes
org.springframework.security.oauth2.core.user.DefaultOAuth2User.<init>()
org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider.authenticate()- User attributes processing
- Authorities assignment
- OAuth2User object creation
// In DefaultOAuth2User constructor
Collection<? extends GrantedAuthority> authorities
Map<String, Object> attributes
String nameAttributeKey // "id" for GitHub// Spring Security Internal Classes
org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken.<init>()
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication()- OAuth2AuthenticationToken creation
- Session storage
- Success handler execution
// In OAuth2LoginAuthenticationToken
OAuth2User principal
Collection<? extends GrantedAuthority> authorities
String authorizedClientRegistrationId // "github"// In WebController.dashboard()
@GetMapping("/dashboard")
public String dashboard(Model model, Authentication auth) {
// BREAKPOINT HERE
if (auth.getPrincipal() instanceof OAuth2User) {
OAuth2User oauth2User = (OAuth2User) auth.getPrincipal();
// Debug oauth2User attributes
Map<String, Object> attributes = oauth2User.getAttributes();
String name = oauth2User.getAttribute("name");
String email = oauth2User.getAttribute("email");
}
}// In OAuth2Controller.getOAuth2User()
@GetMapping("/api/oauth2/user")
public ResponseEntity<?> getOAuth2User(@AuthenticationPrincipal OAuth2User principal) {
// BREAKPOINT HERE
if (principal == null) {
return ResponseEntity.status(401).body(Map.of("error", "Not authenticated"));
}
// Debug principal attributes
Map<String, Object> attributes = principal.getAttributes();
String provider = getProvider(principal);
}- Set breakpoints in Spring Security classes (add to IDE)
- Start application in debug mode
- Open browser:
http://localhost:8081/login - Click "GitHub" button
Breakpoint: OAuth2AuthorizationRequestRedirectFilter.doFilterInternal()
Variables to inspect:
- authorizationRequest.getAuthorizationUri()
- authorizationRequest.getClientId()
- authorizationRequest.getRedirectUri()
- authorizationRequest.getState()
Breakpoint: OAuth2LoginAuthenticationFilter.attemptAuthentication()
Variables to inspect:
- request.getParameter("code")
- request.getParameter("state")
- authorizationRequest (from session)
Breakpoint: DefaultAuthorizationCodeTokenResponseClient.getTokenResponse()
Variables to inspect:
- tokenRequest.getAuthorizationExchange()
- HTTP request entity
- HTTP response entity
- accessToken.getTokenValue()
Breakpoint: DefaultOAuth2UserService.loadUser()
Variables to inspect:
- userRequest.getAccessToken()
- HTTP request to user info endpoint
- userAttributes map
- nameAttributeKey
Breakpoint: WebController.dashboard()
Variables to inspect:
- auth.getPrincipal() (OAuth2User)
- oauth2User.getAttributes()
- Session ID
- Open DevTools (F12)
- Go to Network tab
- Start OAuth2 flow
- Monitor requests:
- Redirect to GitHub
- GitHub callback
- Dashboard redirect
- Burp Suite or OWASP ZAP for detailed HTTP analysis
- Wireshark for network packet analysis
// Breakpoint in OAuth2ErrorResponseErrorHandler
public void handleError(ClientHttpResponse response) {
// Debug HTTP error response
String responseBody = // read response body
HttpStatus statusCode = response.getStatusCode();
}// Breakpoint in DefaultOAuth2UserService
try {
ResponseEntity<Map<String, Object>> response = restOperations.exchange(request, PARAMETERIZED_RESPONSE_TYPE);
} catch (OAuth2AuthorizationException ex) {
// Debug OAuth2 exception
OAuth2Error error = ex.getError();
}// Debug session storage
HttpSession session = request.getSession();
SecurityContext securityContext = (SecurityContext) session.getAttribute("SPRING_SECURITY_CONTEXT");
Authentication authentication = securityContext.getAuthentication();logging.level.org.springframework.security.oauth2=TRACE
logging.level.org.springframework.web.client=DEBUG
logging.level.org.springframework.http.client=DEBUG// Only break when specific conditions are met
auth.getPrincipal() instanceof OAuth2User// Add to IDE watch window
((OAuth2User) auth.getPrincipal()).getAttributes()
request.getSession().getId()
SecurityContextHolder.getContext().getAuthentication()// Add temporary logging
log.debug("OAuth2 User: {}", oauth2User.getAttributes());
log.debug("Session ID: {}", request.getSession().getId());
log.debug("Access Token: {}", accessToken.getTokenValue());This debugging guide will help you trace the complete OAuth2 flow from authorization request to user session creation, allowing you to see exactly how Spring Security handles the token exchange and user info retrieval internally.