53

I'm trying to add basic authentification to my angular2 app.

public login() {
    // Set basic auth headers
    this.defaultHeaders.set('Authorization', 'Basic ' + btoa(this.username + ':' + this.password));

    console.log('username', this.username)
    console.log('password', this.password)
    console.log(this.defaultHeaders)

    // rest is copy paste from monbanquetapiservice
    const path = this.basePath + '/api/v1/development/order';        

    let req = this.http.get(path, { headers: this.defaultHeaders });
    req.subscribe(
        _ => { },
        err => this.onError(err)
    );
}

What I expect to see is a GET request with the Authorizationheader I put.

But what I see is first a OPTIONS with this headers:

OPTIONS /api/v1/development/order HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36
Access-Control-Request-Headers: authorization, content-type
Accept: */*
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6,fr;q=0.4

Since my server doesn't allow OPTIONS on this url, I get an error.

I know that some methods like PUT or POST send first an OPTIONS method to preflight the request, but GET doesn't.

Why does angular2's http send a OPTIONS first?

Thanks.

New
  • 675
  • 1
  • 11
  • 21
jeanpaul62
  • 9,451
  • 13
  • 54
  • 94
  • Looks like a dup of http://stackoverflow.com/questions/1256593/why-am-i-getting-an-options-request-instead-of-a-get-request – Günter Zöchbauer Apr 01 '16 at 10:16
  • This is similar enough to https://stackoverflow.com/questions/12111936/angularjs-performs-an-options-http-request-for-a-cross-origin-resource – Serj Sagan Aug 14 '17 at 02:21
  • Make sure there is a trailing slash, as mentioned here in https://stackoverflow.com/a/50062221/6748184 – user42488 Apr 27 '18 at 12:21

2 Answers2

85

This is the way CORS works (when using cross domain requests). With CORS, the remote Web application (here the one with domain mydomain.org) chooses if the request can be served thanks to a set of specific headers.

The CORS specification distinguishes two distinct use cases:

  • Simple requests. This use case applies if we use HTTP GET, HEAD and POST methods. In the case of POST methods, only content types with the following values are supported: text/plain, application/x-www-form-urlencoded and multipart/form-data.
  • Preflighted requests. When the ‘simple requests’ use case doesn’t apply, a first request (with the HTTP OPTIONS method) is made to check what can be done in the context of cross-domain requests.

It's not Angular2 that sends the OPTIONS request but the browser itself. It's not something related to Angular.

For more details, you could have a look at this article:

battmanz
  • 2,266
  • 4
  • 23
  • 32
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • 2
    I am sending a `GET` request, but I still have this preflight. I know about preflight for PUT and sometimes POST methods, but GET shouldn't have one. That's why I thought it was some angular thing which added this OPTIONS preflight – jeanpaul62 Apr 01 '16 at 10:26
  • 12
    I think that it's because of the `Authorization` header... Because of it, you're in the case of a preflight request and not a simple request. – Thierry Templier Apr 01 '16 at 10:34
  • 2
    In fact, that's the case when you have a custom header (not something sent under the hood by the browser)... – Thierry Templier Apr 01 '16 at 10:36
  • 2
    GET requests also use preflight if you have a content-type that is not in the list above, e.g application/json. I successfully avoided the OPTIONS request by using text/plain, even with a JSON source. – Wolfgang Stengel Feb 02 '18 at 15:41
  • @ThierryTemplier 's reply here is honestly an answer in and of itself. Removing extra headers that I was adding by default in my interceptor was the culprit. – Jhayes2118 Dec 05 '19 at 16:47
  • I had an Angular app specific issue where touching the request with `HttpInterceptor` caused it create a OPTIONS requets intead of plain GET. More information here https://stackoverflow.com/a/61367478/315168 – Mikko Ohtamaa Apr 22 '20 at 14:23
7

Why am I getting an OPTIONS request instead of a GET request?

That is a CORS preflight request that is generated by the browser itself.

See also
- How to disable OPTIONS request?

The server needs to be configured to support CORS requests, only then the actual GET request is sent by the browser after the OPTIONS request.

See also
- "No 'Access-Control-Allow-Origin' header is present on the requested resource" - https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Access-Control-Allow-Credentials

Indicates whether or not the response to the request can be exposed when the credentials flag is true. When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials. Note that simple GET requests are not preflighted, and so if a request is made for a resource with credentials, if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Nice answer, but something strange happened to me, when I issue HTTP request to GitHub.com API, there is no preflight request, but when I do it with my own service API, all requests have preflight request! Do you know what's the reason? – Mohammad Kermani Feb 06 '18 at 13:35
  • GitHub probably provides the expected headers in the response, while your service API doesn't. – Günter Zöchbauer Feb 06 '18 at 13:40
  • Yes, It's possible. But how does Chrome know? It at least should make the first Preflight request to consider – Mohammad Kermani Feb 06 '18 at 14:32
  • 2
    If a preflight request is made depends on some criteria. See Thierry's answer about simple and preflight request. – Günter Zöchbauer Feb 06 '18 at 14:34