1

I'm using token authentication within my app to access the magento API. I do the following setup in postman and it works fine: enter image description here

However using jQuery post I consistently get a 400 error back as it doesn't seem to support HTTP verb OPTIONS for preflight (I have a CORS config for nginx). I've tried:

$.ajax({
 method: "POST",
 url: `myip/index.php/rest/V1/integration/admin/token`,
 data: {username: 'ember-app', password: 'ember-app2'},
}).done(function(response) {
 alert(response);
});
$.ajax({
 method: "POST",
 url: `myip/index.php/rest/V1/integration/admin/token?username=ember-app&password=ember-app2`
}).done(function(response) {
 alert(response);
});
$.post(
 'myip/index.php/rest/V1/integration/admin/token', 
 {username: 'ember-app', password: 'ember-app2'},
 function(response) { alert(response); }
);

I've also tried JSON.stringify around the object. Why does it work in postman but in xhr I constantly get a 400 error? Furthermore this request then triggers another request for a GET with returns a cors error. Some my $.post causes this in the console:

enter image description here

Here's some cURL responses:

curl -H "Origin: http://localhost:4200" \
 -H "Access-Control-Request-Method: POST" \
 -H "Access-Control-Request-Headers: X-Requested-With" \
 -d '{"username": "ember-app", "password": "ember-app2"}'\
 -X OPTIONS --verbose https://myhost/index.php/rest/V1/integration/admin/token

gives a response that is:

{"message":"Request method is invalid."} 

Same with:

curl -H "Origin: http://localhost:4200" \
 -H "Access-Control-Request-Method: POST" \
 -H "Access-Control-Request-Headers: X-Requested-With" \
 -X OPTIONS --verbose https://myhost/index.php/rest/V1/integration/admin/token?username=ember-app&password=ember-app2

However doing a normal curl post works fine:

curl -H "Content-Type: application/json" -X POST -d '{"username":"ember-app","password":"ember-app2"}' https://myhos/index.php/rest/V1/integration/admin/token
asked Jul 13, 2016 at 10:05
2
  • Furthermore $.post('myip/index.php/rest/V1/integration/admin/token?username=ember-app&password=ember-app2', function(response) { console.log(response); }); gives me a 200 but all the aforementioned methods also trigger a GET on the URL which returns a CORS error Commented Jul 13, 2016 at 10:12
  • Can you share your CORS config for Nginx too please ? Commented Jul 15, 2016 at 12:52

3 Answers 3

5
+400

A request is identified as a cross-origin HTTP request when it requests a resource from a different domain than the one which serves the first resource. For security reasons, cross-origin HTTP requests initiated from within scripts are restricted in browsers.

The Cross-Origin Resource Sharing (CORS) mechanism from the W3C defines a standard which give web servers cross-domain access controls that enable secure cross-domain data transfers. It works by adding new HTTP headers that allow servers to defines the set of origins that are permitted to access that information using a web browser.

Additionally, some HTTP requests are considered by default non-secure when they can modify user data. These requests are automatically preflight in web browsers. That means before a request is sent, a preflight request with the OPTIONS verb will be sent by the browser to the other domain server in order to determine whether the actual request is safe to send or not. Upon approval from the server, the actual request is sent.

When you're using Postman, your actual request is sent and that's it. No CORS protection or anything, Postman is not a web browser. It just works.

When you're using jQuery to make an AJAX call in a script from you web browser, it'll follow the CORS standard and tag your request are unsafe, which means it should be preflight. It'll then send a first request to your server with the OPTIONS method to check if your actual request is safe. These requests needs to be allowed on your web server (which seems to be Nginx).

You can check this example on how to enable CORS on Nginx and maybe compare it with your actual configuration. A basic wide-open configuration would be (I added some comments):

location / {
 // OPTIONS requests.
 if ($request_method = 'OPTIONS') {
 // URI that may access the resource.
 add_header 'Access-Control-Allow-Origin' '*';
 // Methods allowed when accessing the resource.
 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
 // Headers that can be used when making the actual request.
 add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
 // Cache the preflight result for 20 day.
 add_header 'Access-Control-Max-Age' 1728000;
 add_header 'Content-Type' 'text/plain charset=UTF-8';
 add_header 'Content-Length' 0;
 return 204;
 }
 // POST requests.
 if ($request_method = 'POST') {
 // URI that may access the resource.
 add_header 'Access-Control-Allow-Origin' '*';
 // Methods allowed when accessing the resource.
 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
 // Headers that can be used when making the actual request.
 add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
 }
 // GET requests
 if ($request_method = 'GET') {
 // URI that may access the resource.
 add_header 'Access-Control-Allow-Origin' '*';
 // Methods allowed when accessing the resource.
 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
 // Methods allowed when accessing the resource.
 add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
 }
}

If everything on the server-side is in order, you should adjust your jQuery request to match what's expected on the server.

jQuery.ajax({
 url: 'https://host/rest/V1/integration/admin/token',
 data: JSON.stringify({"username": "ember-app", "password": "ember-app2"}),
 contentType: "application/json",
 method: 'POST'
}).done((response) => {
 alert(response);
})
answered Jul 15, 2016 at 13:27
Sign up to request clarification or add additional context in comments.

7 Comments

thanks for your answer. That's the exact config I used for nginx. In fact, doing a CORS request to other parts of the API works fine (for example, /rest/V1/guest-carts/ works absolutely fine.
Does all your API endpoints use https (for example https://myhost/index.php/rest/V1/guest-carts/ or only the endpoints relative to authentication?
they all use HTTPS. If we set up a chat I can give you the URL so you can see it for yourself
Sure, let's continue in a chat.
I edited my answer to add a fix on the jQuery request since everything seems to be in order on the server-side.
|
0

It looks like the CORS error is a red herring in this instance.

You mention Magento endpoint /V1/integration/admin/token which is used for token generation.

You do not need to use this within your app.

Instead this can be a multi step process.

  1. Generate the token http://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-token.html#auth-request

  2. Store the token in a config file

  3. For any web API request specify the token in the Authorization request header with the Bearer HTTP authorization scheme. http://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-token.html#web-api-access

answered Jul 15, 2016 at 13:47

Comments

0

Include below lines in Magento .htaccess file, present in the root folder of Magento. It worked for me.

Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"
# Added a rewrite to respond with a 200 SUCCESS on every OPTIONS request.
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ 1ドル [R=200,L]
alexander.polomodov
5,53414 gold badges44 silver badges48 bronze badges
answered Oct 16, 2017 at 13:27

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.