24

I'm trying to connect/ do a POST request to an API with Angular2, It's a very simple API with a Basic Authentication password. When disabling the password on the api everything works like expected. But when I enable the Basic Authentication Angular can no longer connect to the API. In Postman everything works. I tried the following without success.

I've got two headers "Content-Type" and "Authorization"

headers.append("Content-Type", "application/x-www-form-urlencoded");

I've tried these two headers.

headers.append("Authorization", "Basic " + btoa(Username + ":" + Password)); 
headers.append("Authorization", "Basic VXNlcm5hbWU6UGFzc3dvcmQ=");

The only thing I can find is that in the RAW request headers there's only a line with the header names but the values are missing:

Access-Control-Request-Headers: authorization, content-type

Raw headers:

#Request Headers
OPTIONS /shipment HTTP/1.1
Host: api.example.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Access-Control-Request-Headers: authorization, content-type
Accept: */*
Referer: http://localhost:4200/address
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,nl;q=0.6

Hope someone can help

Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
Sephen
  • 1,111
  • 3
  • 16
  • 38

5 Answers5

26

Simplified version to add custom headers to your request:

import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';

@Injectable()
export class ApiService {

   constructor(private _http: Http) {}

   call(url): Observable<any> {
      let username: string = 'username';
      let password: string = 'password';
      let headers: Headers = new Headers();
      headers.append("Authorization", "Basic " + btoa(username + ":" + password)); 
      headers.append("Content-Type", "application/x-www-form-urlencoded");
      return this._http.post(url, data, {headers: headers})
    }
}

It's hard to determine where you went wrong, because the lack of code of the actual http call you do. But this example should work for you

Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
  • I think that an issue is inside of _normalizedNames {"authorization" => "Authorization"}. It shall be {"authorization" => "basic VXNlcm5hbWU6UGFzc3dvcmQ"}. – Skyware Apr 28 '17 at 06:32
  • @Skyware Headers are case insensitive :) – Poul Kruijt Apr 28 '17 at 06:38
  • That`s good to know. However, It should be normalized to "authorization" => "basic xxx" not to "authorization" => "Authorization". Angular 2 normalize an authorization header badly. – Skyware Apr 28 '17 at 06:42
  • Ahh, that's what you meant. And yes, I agree with you – Poul Kruijt Apr 28 '17 at 06:58
  • I think that the solution is on back-end side as the solution mentioned here http://stackoverflow.com/questions/39408413/angular2-http-post-how-to-send-authorization-header – Skyware Apr 28 '17 at 07:00
  • I had to assign the new headers like this in order to make it work: `headers = headers.append(...);` – John Dec 31 '18 at 08:54
3

jrcastillo suggested another option here

I spent so many hours trying to fix this and this one liner solved my problem.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}

I was a bit more specific in the end as this effected my /login path so I did the following instead:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.OPTIONS, "/api/**");
}
rjdkolb
  • 10,377
  • 11
  • 69
  • 89
2

I had same problem in my application.

As you can see the request that is sended is not POST but OPTION ( pre verification)

https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS

You must allowed the OPTIONS request at your API side. If you have Spring application you can just add this to Spring Security configuration :

    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                **.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()**
(..)

}

In my case it works

VANILKA
  • 634
  • 1
  • 13
  • 32
2

This solved my issues:
Angular2 http post - how to send Authorization header?

Ok. I found problem.

It was not on the Angular side. To be honest, there were no problem at all.

Reason why I was unable to perform my request succesfuly was that my server app was not properly handling OPTIONS request.

Why OPTIONS, not POST? My server app is on different host, then frontend. Because of CORS my browser was converting POST to OPTION: http://restlet.com/blog/2015/12/15/understanding-and-using-cors/

With help of this answer: Standalone Spring OAuth2 JWT Authorization Server + CORS

I implemented proper filter on my server-side app.

Thanks to @Supamiu - the person which fingered me that I am not sending POST at all.

Community
  • 1
  • 1
Skyware
  • 352
  • 1
  • 7
  • 16
0

The problem is with the backend server. Any browser sends a preflight request making a cross-origin request. The backend server in this case is not handling the preflight request successfully. Try doing the cors configuration on the backend server. That will resolve this issue.

Siddhant
  • 687
  • 1
  • 8
  • 15