In one of my REST services, I make use of Spring Security to validate the token that is being passed in the header. However, spring is unable to find the "Authorization" header, even though it is there. This was not a problem when testing in test, and even locally but when we deployed to PROD we get this issue.
As an alternative/workaround I removed Spring security and instead tried to do the validation of my token in the actual endpoint before continueing with the rest of the request like such:
@PostMapping(value="/create",consumes="application/json; charset=utf-8")
@CrossOrigin
public ResponseEntity createAccount(@RequestBody MerchantAccount merchantAccount,@RequestHeader(name="Authorization") String token) {
log.info("Checking User Token");
if(!jwtUtil.isAuthorizedToken(token))
return ResponseEntity.status(401).build();
//some creating Account Logic
}
If I did the above once again it would work in TEST and on LOCAL but not in PROD. Error that I would get back would be "Missing Authorization header". But yet again it is present. (Tested from postman to).
After some research, I saw that I could add ",required=false" so spring would not check for it, but then still there was no token to extract.
The only difference between PROD and TEST and my local is the following:
Java version
java version on test:java version "1.6.0_32"
java version on PROD: java version "1.8.0_121"
java version on local:java version "1.8.0_221"
On Test we use HTTP and PROD it's HTTPS. Spring Security Version in POM file is 5.2
EDIT In my web config I do have a section that allows for the "Authorization" header to be present as seen below.
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));//YOLO Allow all origins, we can change this once we go to prod
configuration.setAllowedMethods(ImmutableList.of("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH","OPTIONS"));//Allowed Methods
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type","Access-Control-Request-Headers","Access-Control-Request-Method",
"Accept","Access-Control-Allow-Headers"));//Allowed Headers
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Update On TEST & LOCAL when I iterate through headers in the request filter (as seen below)
@Component
@Service
public class JwtRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
logger.info("Done Getting Headers");
Collections.list(request.getHeaderNames()).forEach(item -> logger.info("header name is " + item));
logger.info("Done Getting Headers");
boolean isAccessToken = true;
final String requestTokenHeader = request.getHeader("authorization");//This is null as the Authorization header is not found in request
}
I get the following output. TEST & LOCAL
On PROD I get the following:
Please help.
After wandering galaxies....
I've fixed it using this:
@Configuration
@EnableWebSecurity
public class Config extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and() /*.other stuff */;
}
}
Basically you need to enable cors()
with the http
object..
and then there are multiple ways to handle the cros origin for each controller/method or globally.
My issue was like this:
Whenever I make request from postman it worked & the "Authorization"
key in header was always present, debugged it using request filter just like you.
However, each time request made form front end app (react) the browser prevented the"Authorization"
key every single time...
To configure it globally:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/greeting-javaconfig")
.allowedOrigins("http://localhost:8080");
}
};
}
Or, controller level,
@CrossOrigin(origins = "http://localhost:8080")
@GetMapping("/greeting")
public String greeting() {
return "works!";
}
Ref:
SO answer, Spring Official Guide
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With