A while ago I created a chrome extension called MalOnTheGo. It has been working well however chrome is now dropping support for the way I access resources from an API. The Chromestatus for the drop can be found here. They are dropping support for a format of urls called Embedded Credentials. I have looked for alternatives however I haven't been able to find anything.
In the API documentation they specify formatting the link in the same way I do using jQuery with the username and password parameters like this :
"Usage Examples:
CURL:
curl -u user:passwordhttps://myanimelist.net/api/account/verify_credentials.xml
This is one of the code snippets that chrome is alerting me will not work at some point in June.
function verifyCredentials(username, password, error, success) {
$.ajax({
"url": "https://myanimelist.net/api/account/verify_credentials.xml",
"error": error,
"username": encodeURIComponent(username),
"password": encodeURIComponent(password),
"success": success
});
}
The API's documentation states that this is the way to access that resource.
Is there anything I can change on my end or is this the only way I can use it and the API developers need to update their implementation?
Any alternatives to what I currently have would help
Thanks
You may find CORS to be helpful for making a cross-domain request to verify credentials. There is a lot of helpful info in this tutorial:
https://www.html5rocks.com/en/tutorials/cors/
You can still use ajax to make your request, you will just need to add some more headers for authentication. There is a section specifically for Chrome extensions as well:
https://www.html5rocks.com/en/tutorials/cors/#toc-cross-domain-from-chrome-extensions
Related
I don't know if this is a duplicate post or not, sorry if it is. I'm using jquery.getJSON to load a json on my server which works just fine. Although, if I try and load a json file on a different server it doesn't work. I know I don't have any code here (because there's not much point) but I just want to know if I'm using it wrong or if it isn't supposed to load external files. I'm using the iOS Safari browser if that effects anything.
EDIT: I've looked at the console (idk what the error thing really means, it's just red with an x by the url it's trying to get the json from) and it looks like it's not actually receiving the data. Plus, do remember I'm on iOS, not desktop so I couldn't look at the console in the "Develop tab :P
EDIT 2: Great! I think I got it working! http://skitty.xyz/getJSON/
You're most likely encountering a path issue; the purpose of $.getJSON is to acquire data via http GET request so yes, it is intended to work remotely. To diagnose your issue, make certain you can access the json file in your browser first: http://domain.com/my_data.json. If that works, use that as the URL you pass into $.getJSON:
$.getJSON( 'http://domain.com/my_data.json', function(data) {
// do something with your data
});
http://api.jquery.com/jquery.getjson/
jquery.getJSON uses ajax which is all about external resources. Here's a couple things to check for if it's not working on an external resource:
1: Is the path you specified correct? The usage is jquery.getJSON(path, callback). The path should be something you can just drop in your browser and see. If an incorrect path is your problem, you'll see a 404 in the console.
2: Is the resource http and your site https? Non-secure resources on secure pages will get blocked by browser security features. You'd see a error to this effect in the console.
3: Is CORS (Cross-origin resource sharing) enabled for your site on the external resource? Servers will sometimes use a whitelist of IPs and domains to determine what origins are allowed to make requests of it. You'd also see an error to this effect in the console.
There probably some other things to look for but this is where I'd start.
Also, by all means, use the debugging features of Safari to LQQK at the actual HTTP data-streams that are passing back-and-forth in response to what you're doing. (You might need to click on a preference to see the "Develop" menu, which will take you to "Show Web Inspector" and its Network tab.)
This approach will instantly answer many questions that a JavaScript-centered approach will not so-readily tell you. (And of course, you can look at the JavaScript console too ... and at the same time.) "The actual data streams, please." Safari will tell you "exactly what bytes" your app actually sent to the server, and "exactly what bytes" the server sent in return. "Priceless!™"
Are you saying you are using jquery ajax request to load some json data from a server?
check the "not working server" has the same end point as your server.
Check if the url you want to get data from is correct.
check if console logged any errors.
Also quote from http://api.jquery.com/jquery.getjson/
"Additional Notes:
Due to browser security restrictions, most "Ajax" requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, port, or protocol.
Script and JSONP requests are not subject to the same origin policy restrictions."
I am unable to enable CORS on any resources from AWS Api Gateway.
I used the "Enable Cors" button present on the web UI:
But attempting to use in development or production yields:
I'm using jQuery 2.2.4 and the method $.post.
What's going wrong?
UPDATE: test staging:
SUCCESS UPDATE:
AWS documentation can be quite large. What I failed to realize is that you must EXPORT a client generated SDK which has a global variable that generates methods based on the resources you provided. As such, I can FINALLY return a succesfull result when I use THIS code:
const apigClient = apigClientFactory.newClient();
apigClient.purchaseTokenPost({}, card, {})
.then(function(result){
console.log(result);
}).catch(function(result){
console.log(result);
});
I found that even for an 'unsecured' api call, i.e. one that your didn't secure with an API key (like I did to test something out), once I enabled cors it would only work if I created an API key and sent it in with the request - easy to do, may want to give it a try.
ADDL INFO:
Here is a sample jquery that worked for me after I enabled CORS on the endpoint:
function loadData() {
$.ajax({
type: "GET",
cache: false,
url: "https://k4t999edod.execute-api.us-east-1.amazonaws.com/prod/myapicall",
crossDomain: true,
dataType: "json",
headers: { 'x-api-key': 'xoeNNQ9475PCAgLtNP18cTv6YTWWB2JFfOe', 'X-Amz-Date': '1/1/2000', 'X-Amz-Security-Token': 'xoeNNQ9475PCAgLtNP18cTv6YTWWB2JFfOe' },
success: function (response) {
//do something here.
}
});
}
Note I included the API key in two places (I scrambled the real ones)
CORS seems to be setup correctly for your method. I tested with this tool:
http://client.cors-api.appspot.com/client (Enter your invoke URL, the POST dropdown, and you can confirm the success "onload" callback is triggered)
Can you try making your request with plain JavaScript to narrow down if it's an issue with jQuery? See: A CORS POST request works from plain javascript, but why not with jQuery?
Edit:
Found this on http://enable-cors.org/server_awsapigateway.html. Looks like the One-Click CORS button in API Gateway isn't compatible with jQuery:
Amazon API Gateway adds support for CORS enabling through a simple button in the API Gateway console. Unfortunately that button has a partial behavior, thus setting CORS correctly only for 200 answer (so not other HTTP status codes) and ignoring JQuery header support. The best solution considered so far is about avoding to use the CORS button and set configurations manually. This can be achieved in a couple of steps:...
(Final) Edit: This is a bug with API Gateway not applying header mappings when the integration returns an error response. This has been a known issue for quite a while: https://forums.aws.amazon.com/thread.jspa?threadID=220324&tstart=0
I have read about CORS many times in the past, and understand what it is. I am currently trying to make a POST request to an endpoint that I have been provided, but I keep getting a CORS error.
I have been ensured that the POST request can be made by the owner of the endpoint, so I want to confirm I am not doing anything wrong by checking on this forum.
this is the latest code that I am using:
$.post({
url: "http://working-api-apparently.com",
data: {
"name": "Paul",
"about": "I want to fix this",
"urls":"['paul.com', 'paul2.com']"
},
contentType:"application/json"
});
I have also tried using a callback with jsonp, but this doesnt work as the endpoint doesnt allow GET requests.
The instructions I have been provided are:
POST to http://working-api-apparently.com
With Content-Type set to "application/json", and a JSON document as body with the following keys:
"name": Your real name as a String
"about": about as string
"urls": Array of Strings
I have tried writing the request in both plain javascript and also using jquery. Can anyone help and let me know what I am doing wrong before I respond by saying it is not working due to a fault on their end.
Also, I am making this request from my local machine, but also tried from a http: address
You are claiming to be sending JSON, but you aren't actually passing JSON.
To do that, you need to encode the data:
data: JSON.stringify({
"name": "Paul",
"about": "I want to fix this",
"urls":"['paul.com', 'paul2.com']"
}),
Fixing that is unlikely to resolve cross origin issues though. It is possible that the instructions are you are following are for a generic REST client and that the server doesn't provide the CORS headers that are required for you to do cross origin requests from JS in a web page. (These are required because you aren't making the request, you are asking the user's browser to make it with the user's identity).
I trying to make an ajax request to another domain, it already works, but now I have another problem...
This is my code:
function getChannelMessages(channel) {
jQuery.support.cors = true;
$.ajax(channel, {
cache : true,
type : "get",
data : _channels[channel].request,
global : false,
dataType : "jsonp text xml",
jsonp : false,
success : function jsonpCallback (response) {
console.log(response);
updateChannelRequest(channel);
//getChannelMessages(channel);
}
});
}
As I said, it already works, but the problem is the server returns an XML (Is not my server, is another server from another company - a web service - so I can not change what it returns) and as jsonp expects an json it fails with the error:
SyntaxError: syntax error
<?xml version="1.0"?><ReceiveMessageResponse xmlns="http://q ... />
According to jQuery documentation, adding jsonp text xml should make the magic, converting the response to simple text and then parsing it as XML, but it does not works.
I was already able to make it using YQL, but it has a limit of 10,000 requests per hour, and the system I'm developing will have up to 10 million request per hour. For that same reason, I can not "proxy" in my own server those requests...
FYI: I'm trying to get the newest messages from SQS, so if there is anyway to tell it to return the data as json, it will be easier and better, but I have not find anything either in the documentation...
The plain answer to my question is this: There are only two ways of do this:
Use a proxy. I won't put here all the how-to's to make it, but you can find a lot of information in the web searching for "cors" "cross domains ajax requests" and "yql" (this last is a proxy by Yahoo)
Use CORS. This is Cross-Origin Resource Sharing. That is: activate the server from which you want to get information to sent information to any other domain and to answer to requests from any other domain. To do this you must be the one who manage the server/service.
Those two are the only ways of getting information XML (or any other format) from another domain. To make json cross domain requests:
Use jsonp (Json Padded). I won't explain this (and actually is just extra information since it won't work if the answer from the server is XML - my main problem), cause there is a lot of information on the web.
Unfortunately I was not able to accomplished my goal, cause SQS is not configured to any of this methods... Still, I've got plenty insight of how Cross-Domains Requests works. And I hope this help anyone...
I've posted before on this subject, but after a year of getting on with other things, I've managed to get into a pickle once again. I'll try and give a brief overview of the scenario and the current attempts to make things work:
IIS web server hosting HTML, JS etc. on host: iis.mycompany.com (referred to as foo)
WCF RESTful web services hosted via a Windows Service on host: wcf.mycompany.com (referred to as bar)
The Javascript served from foo works by making RESTful ajax calls (GET or POST depending on the action) to the WCF services on bar, obviously these are cross domain calls as they aren't on the same host.
The Javascript uses the jQuery (1.7.2) framework to manipulate the DOM and perform ajax calls to bar, the expected content type for POSTS is JSON, and the response from GETS is expected to be JSON too (application/json).
Bar has it's WCF services configured using TransportCredentialOnly as the security mode and the transport client credentail type is NTLM, so only authed users to contact the services.
CORS Support has been added to bar's WCF services using an extension to WCF:
http://blogs.msdn.com/b/carlosfigueira/archive/2012/05/15/implementing-cors-support-in-wcf.aspx
We have added additional headers and modfied some that the post already contained based on numerous internet articles:
property.Headers.Add("Access-Control-Allow-Headers", "Accept, Content-Type");
property.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
property.Headers.Add("Access-Control-Max-Age", "172800");
property.Headers.Add("Access-Control-Allow-Origin", "http://iis.mycompany.com");
property.Headers.Add("Access-Control-Allow-Credentials", "true");
property.Headers.Add("Content-type", "application/json");
Sites giving information on enabling CORS suggest that the Access-Control-Allow-Origin response header should be set to "*" however, this is not possible in our case as we make jQuery ajax calls using the following setup:
$.ajaxSetup({
cache: "false",
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
As it turns out you cannot use "*" for the accepted origin when you are using "withCredentials" in the ajax call:
https://developer.mozilla.org/en/http_access_control
"Important note: when responding to a credentialed request, server
must specify a domain, and cannot use wild carding."
Currently in our development lab, this doesn't matter as we can hard code the requests to the IIS (foo) server URL.
The main problem now appears to be attempting POST requests (GET is working using the above configuration). When the browser attempts the POST process, it first sends an OPTIONS header to the server requesting allowed OPTIONS for the subsequent post. This is where we would like to see the headers we've configured in the CORS Support WCF extension being passed back, however we aren't getting that far; before the response comes back as "401 Unauthorized", I believe this is to do with the transport security binding configuration requesting NTLM, but I'm not sure.
Also, I'm not very experienced with this, but I haven't seen much information about POST using application/json content type as opposed to text/plain when performing cross domain requests.
I know that people will probably suggest JSONP as the one true solution, I'm not against different approaches, indeed I encourage anyone to suggest best practices as it would help others reading this question later. However, please attempt to answer the question before suggestion alternatives to it.
Many thanks in advance for anyone who contributes.
peteski
:)
UPDATE:
It appears that Chrome (20.x.x) doesn't suffer the problem of not negotiating NTLM to retrieve the OPTIONS header response from the server, but Firefox (13.0.1) does.
We've also noticed that someone has already posted a bug up on the Firefox forum, which we've added information to:
http://bugzilla.mozilla.org/show_bug.cgi?id=751552
Please vote for this bug to be fixed on the bugzilla site!
Using the following code, we can watch the network trace to see Firefox failing and Chrome working fine:
var url = "http://myWebServiceServer/InstantMessagingService/chat/message/send";
var data = '{ "remoteUserUri" : "sip:foo.bar#mydomain.com", "message" : "This is my message" }';
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.withCredentials = true;
request.setRequestHeader("Content-Type", "application/json");
request.send(data);
console.log(request);
On a separate note, IE8 doesn't support the XMLHttpRequest for cross domain calls, favouring it's own magical XDomainRequest object, so we've got some work to do in changing the client side code to handle IE8 vs the world cases. (Thanks IE8).
/me crosses fingers that Mozilla fix the Firefox bug.
UPDATE 2:
After some digging it appears that IE8's XDomainRequest cannot be used to make cross domain requests where NTLM must be negotiated, this basically means that the security on our WCF binding can't be used thanks to limitations in a web browser.
http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
"No authentication or cookies will be sent with the request"
So, I guess we've taken this as far as it is going to go for now.. It looks like we're going to have to create our own custom token authentication and pass it across to the WCF service in a cookie, or in IE8's case, POST it with the JSON. The WCF service will then have to handle decrypting the data and using that instead of the ServiceSecurityContext.Current.WindowsIdentity we previously had access to with NTLM auth.
I know you said you would rather have the problem itself addressed, but you may consider using a "reverse proxy."
I don't know what technologies you are using, but we use Apache web server and have a Java RESTful API running on a different server that required authentication. For a while, we messed with JSONP and CORS, but were not satisfied.
In the end, we setup an Apache Reverse Proxy and it worked miracles. The web browser believes it is communicating with its own domain and acts appropriately. The RESTful API doesn't know it is being used via a proxy. Therefore, everything just works. And Apache does all the magic.
Hopefully, all web servers have a feature like Apache's reverse proxy.
Here is some documentation on the feature: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html
All we had to do is ensure the mod_proxy module was installed, then add the following lines to our Apache config file:
ProxyPass /restapi http://restfulserver.com/restapi
ProxyPassReverse /restapi http://restfulserver.com/restapi
Then restart the web server and voila!