Monday, April 25, 2016

jQuery AJAX call results in error status 403

Leave a Comment

I'm making a query to a web service using jQuery AJAX. My query looks like this:

var serviceEndpoint = 'http://example.com/object/details?version=1.1'; $.ajax({   type: 'GET',    url: serviceEndpoint,   dataType: 'jsonp',   contentType: 'jsonp',   headers: { 'api-key':'myKey' },   success: onSuccess,   error: onFailure }); 

When I execute this, I get a status error of 403. I do not understand why my call results in having the status code 403. I'm in control of the security on my service and it is marked as wide-open. I know the key is valid, because I'm using it in another call, which works. Here is the call that works:

var endpoint = 'http://example.com/object/data/item?version=1.1'; $.ajax({    type: 'POST',    url: endpoint,    cache: 'false',   contentType:'application/json',   headers: {     'api-key':'myKey',     'Content-Type':'application/json'   },   data: JSON.stringify({     id: 5,     count:true   }),   success: onDataSuccess,   error: onDataFailure }); 

I know these are two different endpoints. But I'm 100% convinced this is not a server-side authentication or permission error. Once again, everything is wide open on the server-side. Which implies that I'm making some mistake on my client-side request.

I feel I should communicate that this request is being made during development. So, I'm running this from http://localhost:3000. For that reason, I immediately assumed it was a CORS issue. But everything looks correct. The fact that my POST request works, but my GET doesn't has me absolutely frustrated. Am I missing something? What could it be?

2 Answers

Answers 1

The reason of 403 error is you are not sending headers. Since you are making a CORS request, you cannot send any custom headers unless server enables these header by adding Access-Control-Allow-Headers to the response.

In a preflighted-request, client makes 2 requests to the server. First one is preflight (with OPTION method) and the second one is the real request. The server sends Access-Control-Allow-Headers header as a response of the preflight request. So it enables some headers to be sent. By this way your POST request can work, because the POST request is a preflighted-request. But for a GET request, there is no preflight to gather Access-Control-Allow-Headers header. So browser doesn't send your custom headers.

A workaround for this issue:

As a workaround, set your dataType and contentType to json as the following:

var serviceEndpoint = 'http://example.com/object/details?version=1.1'; $.ajax({   type: 'GET',    url: serviceEndpoint,   dataType: 'json',   contentType: 'json',   headers: { 'api-key':'myKey' },   success: onSuccess,   error: onFailure }); 

By this way, your get request will be a preflighted request. If your server enables the api-key with Access-Control-Allow-Headers header, it will work.

Sample server configuration for the above request (written in express.js):

res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', '*'); res.setHeader('Access-Control-Allow-Headers', 'api-key,content-type'); res.setHeader('Access-Control-Allow-Credentials', true); 

ADDED:

Actually, contentType should be either application/javascript or application/json while doing a jsonp request. There is no contentType as jsonp.

Answers 2

If you look at the API page for jQuery's Ajax call, it mentions the following in the Content-Type section:

Note: For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.

That page doesn't really mention what a "preflight OPTIONS request" is, but I found some interesting links when looking that phrase up online:

What's intersting is the code example & the CORS image at the HTML5Rocks page. The image shows how the Ajax calls are being made from the JavaScript code to the browser to the server & how the responses are round-tripping between all 3 of those.

We tend to think of JavaScript + Browser = Client, but in the illustration the author is explaining the difference between the web developer's code & the browser developer's code, where the former is written in JavaScript code, but the latter was written using C, C++ or C# code.

A good packet analyzer tool is Fiddler, which would be similar to Wireshark. Either one of those tools, should show you the pre-flight requests which are being sent from the browser to the server. Most likely, that's where your Ajax request is being blocked at by the server with a 403 Forbidden error.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment