jQuery AJAX call results in error status 403
Asked Answered
L

3

18

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?

Look answered 16/4, 2016 at 15:44 Comment(10)
Did you even try opening that url in your browser directly? Are you missing the /data/ part of the url to match the one that works?Yoho
Note that you can't send headers for jsonp request, it is a script request. Are you sure you want jsonp and not json? Also why JSON.stringify() for headers? GET has no request contentType. since there is no body content being sent. You have numerous issues any one of which can be problemYoho
@Yoho I did try opening in the browser. I'm not familiar of any /data/ part I need to include. I litterally just need to pass in the version and api-key. I assumed that I should put the api-key as a header. Do I need to set the data and contentType properties to jsonp? This seems like it should be a simple call. But clearly, I'm botching it and overlooking something. What should the correct call look like?Look
jsonp is a different type of request than ajax and doesn't allow headers. There simply isn't enough known about problem from what is shownYoho
are you using chrome? and what is your back end technology?Coyote
I am using Chrome. All of this is in an index.html file. I'm running the page through lite-server (github.com/johnpapa/lite-server)Look
Just a thought, are you using any ad blockers? That has caused issues with me in the past.Herra
@user1917363 - There are no ad blockers installed.Look
Have you tried the content-type as application/javascript? datatype is jsonp but doesn't seem like content-type should be.Herra
Have you confirmed that you are setting up valid headers? refSkulk
A
24

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 OPTIONS 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 preflight-request. But for a GET request, there is no preflight to gather Access-Control-Allow-Headers header and browser doesn't send your custom headers in this case.

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.

Azucenaazure answered 23/4, 2016 at 21:17 Comment(2)
where should the res.setHeader code be written? Also, what kind of object is res?Garnishment
@Garnishment it will be in the server side. here is the docs for res in express server.Azucenaazure
M
1

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.

Marsupium answered 24/4, 2016 at 3:8 Comment(0)
F
0

See also this post that discusses the problem of the Google Translate extension appending extraneous HTML to certain page elements.

For example, in the above-linked case, Google Translate appended these lines

<p>&nbsp;</p>
<div id="gtx-trans" style="position: absolute; left: -28px; top: -8px;">&nbsp;</div>

to the TinyMCE editor contents. When the user-entered data was sent to the back-end, it included the Google Translate additions, which precipitated the 403 error.

Faroff answered 11/5, 2023 at 16:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.