Question
Recently i have introduced JWT authentication to my Springboot and Angualr2 based App. In There i tried to do a POST request by passing the JWT token as below in my Angualr code
save(jobId: number, taskId: number, note: Note) {
return this.http.post(environment.APIENDPOINT + '/jobs/' + jobId + '/tasks/' + taskId + '/notes', note, this.setHeaders()).map((response: Response) => response.json());
}
private setHeaders() {
// create authorization header with jwt token
let currentUser = JSON.parse(localStorage.getItem('currentUser'));
console.log("Current token---"+ currentUser.token);
if (currentUser && currentUser.token) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('authorization','Bearer '+ currentUser.token);
let r = new RequestOptions({ headers: headers })
return r;
}
}
However in the server side it returns status code 401. The issue is in the Springboot side it checks the authorization header as below and it returns null
String authToken = request.getHeader("authorization ");
Then i had a look at the request header and it has the authorization header under Access-Control-Request-Headers as below. But it is not visible to the server side.
Then i read further and found that this could be an issue with CORS configuration. So i have modified my CORS configuration filter to have addExposedHeader as below
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addExposedHeader("authorization");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
//config.addExposedHeader("Content-Type");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
Still the server complains that it can not find the Authorization header. Did i miss any thing here? Appreciate your help
Solution
After reading the sideshowbarker's comment below, i was able to understand the basics behind the issue. In My Project I have a JWT token filter and inside that it always checks the Authorization header. Then i have modified it as below and now it works as expected
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
try {
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
}else{
String authToken = request.getHeader(this.tokenHeader);
jWTTokenAuthenticationService.parseClaimsFromToken(authToken);
--
}
chain.doFilter(request, response);
}Catch(AuthenticationException authEx){
SecurityContextHolder.clearContext();
if (entryPoint != null) {
entryPoint.commence(request, response, authEx);
}
}
}
Answer
You need to configure the server to not require authorization for OPTIONS
requests (that is, the server the request is being sent to — not the one
serving your frontend code).
That’s because what’s happening is this:
- Your code tells your browser it wants to send a request with the
Authorization
header. - Your browser says, OK, requests with the
Authorization
header require me to do a CORS preflightOPTIONS
to ensure the server allows requests with theAuthorization
header. - Your browser sends the
OPTIONS
request without theAuthorization
header, because the whole purpose of theOPTIONS
check is to see if it’s OK to include that header. - Your server sees the
OPTIONS
request but rejects it with a 401 since it lacks the header. - Your browser expects a 200 or 204 response for the CORS preflight but instead gets that 401. So your browser stops right there and never tries the
POST
request from your code.
Further details:
The Access-Control-Request-Headers
and Access-Control-Request-Method
request headers show in the question indicate the browser’s doing a [CORS
preflight OPTIONS request](https://developer.mozilla.org/en-
US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests).
And the presence of the Authorization
and Content-Type: application/json
request headers in your request are what trigger your browser do that CORS
preflight — by sending an OPTIONS
request to the server before trying the
POST
request in your code. And because that OPTIONS
preflight fails, the
browser stops right there and never attempts the POST
.
So you must figure out what part of the server-side code on the server the
request is being sent to causes it to require authorization for OPTIONS
requests, and change that so it instead responds to OPTIONS
with a 200 or
204 success response without requiring authorization.
For specific help on OPTIONS
-enabling a Spring server in particular, see the
following answers: