Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 accessing REST via Basic Auth throws "Response for preflight has invalid HTTP status code 401"

We are currently trying to access a REST-Endpoint of a Spring Boot app in an Angular2-App, but despite the fact that the Authorization header works in Postman (Authorization/Basic dXNlcjp1c2Vy, for a basic test user with the password user), it does not work when the app tries to access the REST-Endpoint. The Spring-Security is configured as such:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
    builder.inMemoryAuthentication().withUser("user").password("user").roles("USER").and().withUser("admin")
            .password("admin").roles("ADMIN");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().fullyAuthenticated();
    http.httpBasic();
    http.csrf().disable();
}

}

The angular app asks for credentials before making the first request, like so:

loginTest() {
    let headers: Headers = new Headers({'Content-Type': 'application/json', 'Accept': 'application/json'});
    headers.append('Authorization', 'Basic ' + window.btoa(this._username + ':' + this._password));
    console.log(headers);
    return this.http.get('http://localhost:8080/', {headers: headers})
        .map((res:any) => res.json);
}

With localhost:8080 being the Spring Boot app. We already tried adding Content-Policy tags because there were similar problems with an earlier project, like so:

<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' 'self';
connect-src 'self' http://localhost:3000/ http://localhost:8080/ ws://localhost:3000/; img-src 'self' data:;
style-src 'unsafe-inline' 'self'; font-src 'self'"/>

but that didn't work either. The error we get:

XMLHttpRequest cannot load http://localhost:8080/. Response for preflight has invalid HTTP status code 401

When looking at the request via Chrome, this is the Response:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Set-Cookie: JSESSIONID=4659A74A950FE6C99948D8F4CB245E27; Path=/; HttpOnly
WWW-Authenticate: Basic realm="Realm"
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: accept, authorization, content-type
Access-Control-Allow-Credentials: true
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Mon, 04 Jul 2016 07:54:30 GMT

I don't see what the Angular2-App is doing different when compared to PostMan here.

like image 546
Torsten N. Avatar asked May 29 '26 03:05

Torsten N.


1 Answers

I think that your problem is related to CORS. Postman is a chrome plugin so it has the permission to execute CORS requests. It's not the case of your Angular application: it's more restricted.

See this question:

  • how Postman send requests? ajax, same origin policy

In the case of Angular, you need to handle CORS. You have a preflighted request (OPTIONS) that is sent before sending the actual request. I think that in your case, credentials aren't sent into this preflighted request so the server can't authenticate it and returns a 401 status code. This prevents from executing the target request.

I see two solutions:

  • Use the withCredentials parameter to true (available in Angular2 from RC2)

    this.http.get('http://...', { withCredentials: true })...
    
  • Only check security on target requests and not on preflighted ones. It's a configuration to do on the server side.

See these articles for more details:

  • http://restlet.com/blog/2015/12/15/understanding-and-using-cors/
  • http://restlet.com/blog/2016/09/27/how-to-fix-cors-problems/
like image 66
Thierry Templier Avatar answered May 30 '26 17:05

Thierry Templier