imgrooot Posted November 7, 2020 Share Posted November 7, 2020 Basically I am submitting and retrieving data from a 3rd party's API. But every time I submit a form, it gives me this error. Access to XMLHttpRequest at 'https://3rdpartywebsite.com/api' from origin 'https://mywebsite.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. So I have been researching and there seems to be so many different answers. I have tried adding this code to the page but still get an error. <?php // ADD THIS CODE ON THE VERY TOP OF THE PAGE I AM SUBMITTING THE FORM. header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Credentials: true"); header("Access-Control-Max-Age: 1000"); header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding"); header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE"); ?> I have also tried to add this to .htaccess file and still get the same error. Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type" Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS" I was wondering what am I doing wrong? What's the correct way of implementing CORS to my site? Quote Link to comment Share on other sites More sharing options...
requinix Posted November 8, 2020 Share Posted November 8, 2020 CORS is implemented at the place receiving the AJAX call, not the one making it. 3rdpartywebsite.com/api would have to add those headers. Proxy the request: set up an API endpoint on your site that works the same way (at least as far as you care for it to work) which sends the request to that site and returns back its response. Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 8, 2020 Author Share Posted November 8, 2020 37 minutes ago, requinix said: CORS is implemented at the place receiving the AJAX call, not the one making it. 3rdpartywebsite.com/api would have to add those headers. Proxy the request: set up an API endpoint on your site that works the same way (at least as far as you care for it to work) which sends the request to that site and returns back its response. Wow, none of the answers I looked at told me that it's the one receiving the AJAX call are the ones who need to add those headers. As for setting up proxy request, I'm not sure what you mean exactly but I did add a chrome extension allowing CORS to work on my browser. I turned it on and did the ajax call test again. Now I no longer get that error. So it seems to work. I would've assumed that the 3rd party api would be using CORS. Guess I will ask them about it. Quote Link to comment Share on other sites More sharing options...
kicken Posted November 8, 2020 Share Posted November 8, 2020 3 hours ago, imgrooot said: As for setting up proxy request, I'm not sure what you mean exactly Instead of requesting the third-party API directly in your script you request a resource on your domain then you have your server forward that request to the third-party. So, for example, your XMLHttpRequest would be to the URL http://yourdomain.com/third-party/api Then on your server you could either make that point to a PHP script that runs the third-party request and returns the result, or configure your server to proxy the request with something like: ProxyPass /third-party/api "https://3rdpartywebsite.com/api" ProxyPassReverse /third-party/api "https://3rdpartywebsite.com/api" Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 8, 2020 Author Share Posted November 8, 2020 3 hours ago, kicken said: Instead of requesting the third-party API directly in your script you request a resource on your domain then you have your server forward that request to the third-party. So, for example, your XMLHttpRequest would be to the URL http://yourdomain.com/third-party/api Then on your server you could either make that point to a PHP script that runs the third-party request and returns the result, or configure your server to proxy the request with something like: ProxyPass /third-party/api "https://3rdpartywebsite.com/api" ProxyPassReverse /third-party/api "https://3rdpartywebsite.com/api" The thing is this is not a typical API integration. The third party does not provide any API files to added to the server. The only way to connect to this particular third party's API is through a host url they provided. Here is my original ajax code to submit the form's info to that API. <script> var url = "https://3rdpartywebsite.com/api"; $('#submit-form') .submit(function (e) { $.ajax ({ url: url, type: 'POST', data: new FormData(this), processData: false, contentType: false, success: function(data) { alert(data.message); } }); e.preventDefault(); }); </script> In your example, are you prosing that I should change the url to this? <script> var url = "http://yourdomain.com/third-party/api"; $('#submit-form') .submit(function (e) { $.ajax ({ url: url, type: 'POST', data: new FormData(this), processData: false, contentType: false, success: function(data) { alert(data.message); } }); e.preventDefault(); }); </script> And where do I add the two "ProxyPass" lines on the page? In .htaccess file? Because if I do that, it gives me an internal server error. Quote Link to comment Share on other sites More sharing options...
requinix Posted November 8, 2020 Share Posted November 8, 2020 1 hour ago, imgrooot said: The thing is this is not a typical API integration. The third party does not provide any API files to added to the server. That's not weird. It's only the larger companies that tend to provide SDKs for developers. Most of the time all you have to work with is documentation. 1 hour ago, imgrooot said: And where do I add the two "ProxyPass" lines on the page? In .htaccess file? Because if I do that, it gives me an internal server error. Sounds like you don't have mod_proxy installed. If you control the server then you'll have to install that module first. If you don't, and if your hosting provider doesn't give you a way to enable features like mod_proxy, then you might have to go with a pure PHP solution. Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 8, 2020 Author Share Posted November 8, 2020 (edited) 30 minutes ago, requinix said: That's not weird. It's only the larger companies that tend to provide SDKs for developers. Most of the time all you have to work with is documentation. Sounds like you don't have mod_proxy installed. If you control the server then you'll have to install that module first. If you don't, and if your hosting provider doesn't give you a way to enable features like mod_proxy, then you might have to go with a pure PHP solution. I see. So what would a pure PHP solution look like? My hosting provider is telling me that mod_proxy is already installed on the server. So could it be something else? Edited November 8, 2020 by imgrooot Quote Link to comment Share on other sites More sharing options...
kicken Posted November 8, 2020 Share Posted November 8, 2020 4 hours ago, imgrooot said: So what would a pure PHP solution look like? It could look like many things, depending on what you need to accomplish. The simplest thing would just be something like: <?php $url = 'https://3rdpartywebsite.com/api'; $context = stream_context_create([ 'http' => [ 'method' => 'POST' , 'content' => file_get_contents('php://input') ] ]); echo file_get_contents($url, false, $context); Basically you just have PHP make the request to the API via whatever means (native streams, cURL, guzzle, etc) and return the result back. Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 8, 2020 Author Share Posted November 8, 2020 3 hours ago, kicken said: It could look like many things, depending on what you need to accomplish. The simplest thing would just be something like: <?php $url = 'https://3rdpartywebsite.com/api'; $context = stream_context_create([ 'http' => [ 'method' => 'POST' , 'content' => file_get_contents('php://input') ] ]); echo file_get_contents($url, false, $context); Basically you just have PHP make the request to the API via whatever means (native streams, cURL, guzzle, etc) and return the result back. The above code echos an error. Warning: file_get_contents(https://3rdpartywebsite.com/api): failed to open stream: HTTP request failed! HTTP/1.1 411 Length Required in Though I should mention that I am trying to create a customer. So the full url is like this "https://3rdpartywebsite.com/api/createCustomer" Still I shouldn't have to go through all this trouble to make a simple AJAX call to a third party API. Quote Link to comment Share on other sites More sharing options...
requinix Posted November 8, 2020 Share Posted November 8, 2020 13 hours ago, imgrooot said: My hosting provider is telling me that mod_proxy is already installed on the server. So could it be something else? When you put those Proxy commands kicken's gave you into your .htaccess, you said you got an internal server error. What do the server logs have to say about why there was an internal server error? 5 hours ago, imgrooot said: The above code echos an error. Warning: file_get_contents(https://3rdpartywebsite.com/api): failed to open stream: HTTP request failed! HTTP/1.1 411 Length Required in kicken gave you the "simplest thing" that could work. Evidently their API is not a simple thing. 5 hours ago, imgrooot said: Still I shouldn't have to go through all this trouble Says who? The internet isn't some plug-and-play thing. You can't wave a magic wand and suddenly have your site start talking to another site, just like how I can't travel to Finland and suddenly be able to speak Finnish. It will take some degree of work to make this happen. Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 9, 2020 Author Share Posted November 9, 2020 58 minutes ago, requinix said: When you put those Proxy commands kicken's gave you into your .htaccess, you said you got an internal server error. What do the server logs have to say about why there was an internal server error? kicken gave you the "simplest thing" that could work. Evidently their API is not a simple thing. Says who? The internet isn't some plug-and-play thing. You can't wave a magic wand and suddenly have your site start talking to another site, just like how I can't travel to Finland and suddenly be able to speak Finnish. It will take some degree of work to make this happen. I just meant that an API integration should be pretty straightforward process instead of having to find certain hacks to try and make it work. This is my first time dealing with an API that's not SDK based. I guess the issue is mainly on their end. Quote Link to comment Share on other sites More sharing options...
requinix Posted November 9, 2020 Share Posted November 9, 2020 6 hours ago, imgrooot said: Though I should mention that I am trying to create a customer. So the full url is like this "https://3rdpartywebsite.com/api/createCustomer" Er, I missed this before. Whose API are you trying to use? Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 9, 2020 Author Share Posted November 9, 2020 34 minutes ago, requinix said: Er, I missed this before. Whose API are you trying to use? Not sure if i'm allowed to say the company but they are giving a private access to their API that's not available to others. It's essentially to verify customers. I send the data to their them via AJAX call. Here is the full code. <form id="submit-form" method="post" enctype="multipart/form-data"> <fieldset> <label>Last Name *</label> <input type="text" name="LastName" maxlength="300" placeholder="Last Name" /> </fieldset> <fieldset> <label>First Name *</label> <input type="text" name="FirstName" maxlength="300" placeholder="First Name" /> </fieldset> <fieldset> <label>Date Of Birth *</label> <input type="text" name="DateOfBirth" id="datepicker2" placeholder="Choose a date" /> </fieldset> <fieldset> <label>Phone Number *</label> <input type="tel" name="PhoneNumber" maxlength="50" placeholder="123-4567-8901" /> </fieldset> <fieldset> <label>Email Address *</label> <input type="email" name="EmailAddress" maxlength="100" placeholder="Email Address" /> </fieldset> <fieldset> <label>Company Position *</label> <select class="select-category" name="CompanyPosition" > <option value="">Select</option> <option value="President">President</option> <option value="Director">Director</option> </select> </fieldset> <fieldset> <label>Legal Company Name *</label> <input type="text" name="LegalCompanyName" maxlength="500" placeholder="Legal Company Name" /> </fieldset> <fieldset> <label>Doing Business Name As *</label> <input type="text" name="DoingBusinessAsName" maxlength="500" placeholder="Doing Business Name As" /> </fieldset> <fieldset> <label>Corporate Registration Jurisdiction *</label> <select class="select-category" name="CorporateRegistrationJurisdiction" > <option value="">Select</option> <option value="USA" >USA</option> <option value="Canada" >Canada</option> </select> </fieldset> <fieldset> <label>Business Address *</label> <input type="text" name="BusinessAddress" maxlength="500" placeholder="Business Address" /> </fieldset> <fieldset> <label>Photo ID *</label> <input type="file" name="PhotoId" class="input-image"> </fieldset> <fieldset> <input type="submit" name="submit" value="Submit" /> </fieldset> </form> <script> var url = "https://3rdpartywebsite.com/api/CreateCustomer"; $('#submit-form') .submit(function (e) { $.ajax ({ url: url, type: 'POST', data: new FormData(this), processData: false, contentType: false, success: function(data) { alert(data.message); } }); e.preventDefault(); }); </script> That is the code example they showed me. It should work without me doing anything else. But I get that "...blocked by CORS policy" error in the inspect console. Quote Link to comment Share on other sites More sharing options...
kicken Posted November 9, 2020 Share Posted November 9, 2020 7 hours ago, imgrooot said: The above code echos an error. Apparently you need to add the Content-length header yourself, PHP won't add it for you when passing body content. The code I posted was just to get you on the right path, you'll have to troubleshoot/problem-solve yourself to get to a final working solution. 56 minutes ago, imgrooot said: I just meant that an API integration should be pretty straightforward Not necessarily. Since most API's are REST based these days, most places in my experience don't really bother with an SDK. At best, you get documentation of the end points and some example code. At worst you get the "common use case" documentation and have to figure everything else out yourself. The general idea is that anyone that is going to be trying to implement said API knows how HTTP works and knows how to make HTTP requests. If you're not well-versed on HTTP then you fall back to a library that can handle that part of it for you, which for PHP a popular choice these days is Guzzle. It's still up to you to know what request to make and what data to pass however. 1 hour ago, imgrooot said: I guess the issue is mainly on their end. If they have explicitly advertised their API as being AJAX compatible then maybe it is. Maybe they just forgot to add the necessary CORS stuff. Since you mention it's a private API, potentially created just for you, then this is a real possibility. If it's not advertised as being AJAX compatible though then calling it from javascript probably isn't intended and the missing CORS stuff is likely intentional. Quote Link to comment Share on other sites More sharing options...
requinix Posted November 9, 2020 Share Posted November 9, 2020 19 minutes ago, imgrooot said: Not sure if i'm allowed to say the company but they are giving a private access to their API that's not available to others. It's essentially to verify customers. I send the data to their them via AJAX call. "Verify" customers? The API endpoint is "createCustomer"... Here's the deal with Javascript: it's public. Everything is visible for someone to read. Anyone can pull up your HTML and Javascript, see the API call, and start to abuse that. I don't see a hidden input in the form for some sort of API key, but that means (a) there's supposed to be one and you haven't included it yet, or (b) the endpoint is not authenticated. Either way, it really doesn't sound to me like this is the sort of thing that should be run entirely from Javascript. Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 9, 2020 Author Share Posted November 9, 2020 51 minutes ago, requinix said: "Verify" customers? The API endpoint is "createCustomer"... Here's the deal with Javascript: it's public. Everything is visible for someone to read. Anyone can pull up your HTML and Javascript, see the API call, and start to abuse that. I don't see a hidden input in the form for some sort of API key, but that means (a) there's supposed to be one and you haven't included it yet, or (b) the endpoint is not authenticated. Either way, it really doesn't sound to me like this is the sort of thing that should be run entirely from Javascript. "CreateCustomer" would create the customer and return the result message if it's successful or not. The verification will be done manually on their end and they will update this "Customer". At that point I use "GetCustomers" to retrieve that information and find out if it has been verified or not. There is no API key provided. It's strictly submitted through that URL they provided. The form field names are exactly as they wanted. AJAX is one of the methods to submit the form. The other one is CURL but i'm not familiar with that. Now that you mentioned it, yeah this method doesn't seem safe. Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 9, 2020 Author Share Posted November 9, 2020 1 hour ago, kicken said: Apparently you need to add the Content-length header yourself, PHP won't add it for you when passing body content. The code I posted was just to get you on the right path, you'll have to troubleshoot/problem-solve yourself to get to a final working solution. Not necessarily. Since most API's are REST based these days, most places in my experience don't really bother with an SDK. At best, you get documentation of the end points and some example code. At worst you get the "common use case" documentation and have to figure everything else out yourself. The general idea is that anyone that is going to be trying to implement said API knows how HTTP works and knows how to make HTTP requests. If you're not well-versed on HTTP then you fall back to a library that can handle that part of it for you, which for PHP a popular choice these days is Guzzle. It's still up to you to know what request to make and what data to pass however. If they have explicitly advertised their API as being AJAX compatible then maybe it is. Maybe they just forgot to add the necessary CORS stuff. Since you mention it's a private API, potentially created just for you, then this is a real possibility. If it's not advertised as being AJAX compatible though then calling it from javascript probably isn't intended and the missing CORS stuff is likely intentional. Yes it is a private API created just for us. Supposedly the only two compatible methods to submit the form are AJAX and CURL. The AJAX code you see is what they provided to submit the form. I will get more clarification from them tomorrow. Quote Link to comment Share on other sites More sharing options...
imgrooot Posted November 14, 2020 Author Share Posted November 14, 2020 This issue has been resolved. I did not have to do any hack tricks to make it work. The problem was simple. 1. They provided the incorrect URL. 2. All form required fields had to be filled out before submitting. 3. Had to clear my browser's cache before doing a new test. Now it submits the form data to their API just fine. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.