In the new Spring Boot 3.0.1 I'm adding support for CSRF protection by adding this simple configuration as per Spring documentation:
http.csrf().csrfTokenRepository(tokenRepository);
and
@Bean
public CsrfTokenRepository tokenRepository() {
var tokenRepo = CookieCsrfTokenRepository.withHttpOnlyFalse();
tokenRepo.setCookiePath("/");
return tokenRepo;
}
On the front-end side, there is an Angular app with import of the standard library
import {HTTP_INTERCEPTORS, HttpClientModule, HttpClientXsrfModule} from '@angular/common/http';
However I cannot make it work with the standard workflow, like
- Execute request to get XCSRF-TOKEN cookie from the server.
- Extract the token value from the cookie.
- Add X-XSRF-TOKEN header with the extract value from the cookie.
The front-end sends both cookie and header with the same token value and it fails in check:
public final class XorCsrfTokenRequestAttributeHandler ...
private static String getTokenValue(String actualToken, String token) {
byte[] actualBytes;
try {
actualBytes = Base64.getUrlDecoder().decode(actualToken);
}
catch (Exception ex) {
return null;
}
byte[] tokenBytes = Utf8.encode(token);
int tokenSize = tokenBytes.length;
if (actualBytes.length < tokenSize) {
return null;
}
The methods always returns null for
if (actualBytes.length < tokenSize) {
return null;
}
The only way to make it work is to return encoded string to be pasted in the header directly by adding endpoint, like this:
DeferredCsrfToken deferredCsrfToken = repository.loadDeferredToken(request, response);
requestHandler.handle(request, response, deferredCsrfToken::get);
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
return csrfToken.getToken();
So the returned value to be used in header looks like:
ab5tfqabXomGPuLjDQk96mVMZHNOh_JnpPVM4F_hQU1sOMyWW9sLSsCtb72rWNPabyQJ01EpSUsvtctKwcQphWeAJX9ZDPmg
instead of
5adaf830-40e6-43c9-b42a-e36fd713c1a6
Any advice on what I'm missing here?