Complete code for a Spring OAuth2 implementation of Multi-Factor Authentication has been uploaded to a file sharing site at this link. Instructions are given below to recre
One idea that popped to my head:
If session fixation is activated, a new session is created after the user authenticated successfully (see SessionFixationProtectionStrategy). This will also of course create a new csrf token if you use the default HttpSessionCsrfTokenRepository. Since you're mentioning the XSRF-TOKEN header I assume you use some JavaScript frontend. I could imagine that the original csrf token that was used for the login is stored and reused afterwards - which would not work because this csrf token is not valid anymore.
You may try disabling session fixation (http.sessionManagement().sessionFixation().none() or <session-management session-fixation-protection="none"/>) or re-get the current CSRF token after login.
Your CustomOAuth2RequestFactory is putting the previous request in-place of the current request. However, you are not updating the XSRF token in the old request when you make this switch. Here is what I would suggest for the updated CustomOAuth2Request:
@Override
public AuthorizationRequest createAuthorizationRequest(Map<String, String> authorizationParameters) {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session = attr.getRequest().getSession(false);
if (session != null) {
AuthorizationRequest authorizationRequest = (AuthorizationRequest) session.getAttribute(SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME);
if (authorizationRequest != null) {
session.removeAttribute(SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME);
//UPDATE THE STATE VARIABLE WITH THE NEW TOKEN. THIS PART IS NEW
CsrfToken csrf = (CsrfToken) attr.getRequest().getAttribute(CsrfToken.class.getName());
String attrToken = csrf.getToken();
authorizationRequest.setState(attrToken);
return authorizationRequest;
}
}
return super.createAuthorizationRequest(authorizationParameters);
}
I am revisiting this because my initial answer draft got downvoted. This version is further along the same path, which I believe is the right avenue of approach.