I develop a JavaScript application which uses oauth2 authentication. Now I want to load/show an image from server which is behind this authentication mechanism. Therefor I send an xmlHttp-request to the rest-server and get the URI of the image as response.
After the request I try to append the URI to the src of an image and the application responds with 401.
How can I tell the browser to reuse my authentication for this image as well?
This is a part of the xmlHttp-request for getting the URI.
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
xhr.setRequestHeader('Authorization','bearer '+token);
xhr.send(null);
xhr.onreadystatechange = function() {
console.log(xhr);
if (xhr.readyState == 4 && xhr.status == 200) {
var img = document.createElement('img');
img.src = xhr.responseURL;
document.body.appendChild(img);
}
}
Did I forgot something?
An image is a static file and I doubt you're going to be able to get OAuth2 protection when you request it via a simple URL. While you can add OAuth2 information in your URL that's probably not a good thing to do because it will expose to the client all the data which should be private and secure.
Maybe you can consider serving the image from a normal protected endpoint as a byte[] or Base64 string which you can then render in your client if you really need to protect the image itself.
So have a protected endpoint which serves the content of the image itself. Of course, you'd only do this if you actually need the image to be private and secure. If you don't then just let it be public and serve from a separate CDN. It doesn't really need to be behind an OAuth2 system.
Though I came here to search for a better answer than the one I have to offer here are my current solutions:
Serve the image as base64 / json via REST -> supports Oauth2 but will increase file size and just feels very wrong.
Use a cookie to sent the authentication.
Related
On a website we are working on, we have a download link, that must be served to the user. However, when fetching the url the server can either serve an error message in JSON (the appropriate headers and an appropriate http status code will then be set) or serve the file.
Currently, we are using an iframe to download this file, but this prevents us from viewing the error message. While, this can be done in principle, it cannot be done cross-domain and the reading the error data seems to be different between browsers (as the browser will interpret the json as html and create html tags around it)
I have considered using xmlhttprequest2 to download the file, and serve it to the user, however the downloaded file can be large and thus, it must be streamed to the user.
Therefore, I'm looking for a way to either download a file or read the error message depending on the http status code.
API Setup
I'm able to change the API to my wishes, however the API is designed to be a public API and is designed as a REST API. This means, that the API should stay as simple as possible, and workarounds to make specific client-side code work should not have cause any hazzle for other client-side (thus the API and client-side code are decoupled).
The file that is being downloaded is encrypted on the server, and can only be decrypted by information given in the URL. Therefore, chunked transfer is difficult, as extracting a chunk would require the server to decrypt the whole file.
the appropriate headers and an appropriate http status code will then be set
If that statement is correct, you could use the same concept as preflighted requests for Cross-site requests. Preflighted requests first send an HTTP request with the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send or not.
In your case, instead of having an OPTIONS request automatically send, you could send manually an HEAD request. The HEAD method is identical to GET except that the server do not return a message-body in the response. The informations contained in the HTTP headers in response to a HEAD request should be identical to the information sent in response to a GET request. Since you're only fetching the headers and not the body, you would have no problem with large or even any file, nothing is downloaded except the headers.
Then, you can read these headers or even the status code, and depending on the result of this manually preflighted request, decide if you should either stream the file to the user or fetch the error message if you're encountering an error.
A basic implementation without knowledge of your project using status code could be the following:
function canDownloadFile(url, callback)
{
var http = new XMLHttpRequest();
http.open('HEAD', url);
http.onreadystatechange = function() {
if (http.readyState === XMLHttpRequest.DONE) {
callback(http.status);
}
};
http.send();
}
var canDownloadCallback = function (statusCode) {
if (statusCode === 200) {
// The HEAD request returned an OK status code, the GET will do the same,
// let's download the file...
} else {
// The HEAD request returned something else, something is wrong,
// let's fetch the error message and maybe display it...
}
}
You can return to iframe JS code which would send message to parent window via postMessage, in this way you could capture errors in host window. There wouldn't be any problems with cross-domain, and content easily would be streamed to browser as it was before.
You could use single request, return response as a Blob, check Blob.type to determine where to utilize FileReader .result to retrieve JSON text from Blob and display error message, or set src of <img> element using URL.createObjectURL
var result = document.querySelector("div");
fetch("/path/to/resource")
.then(response => response.blob())
.then(blob => {
if (blob.type === "application/json") {
var reader = new FileReader();
reader.onload = (e) => {
result.innerHTML = JSON.parse(e.target.result).error
};
reader.readAsText(blob);
} else {
var img = document.createElement("img");
img.src = URL.createObjectURL(blob);
result.appendChild(img);
}
});
plnkr http://plnkr.co/edit/wrzLNm1Sp4k1mfNrYOlQ?p=preview
In a web page I want to download data from a certain URL.(Well just a google api).
Since I want to a cross domain access, I should use "jsonp".
But the url(google api) only return json which I cannot modify the format.
A "jsonp" request always throws an "Uncaught SyntaxError: Unexpected token : " error.
Of course I can set up a backend server as proxy.
Is there any way to solve this problem only on the client side?
If the data is public and Google has enabled CORS on their servers using the Access-Control-Allow-Origin: * header, then nothing more is required than a simple HTTP request using the XMLHttpRequest object.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.google.com/some.json');
xhr.onload = function(e) {
var data = JSON.parse(this.response);
console.log(data);
}
xhr.send(null);
If the example above fails that means the data isn't public and some kind of authentication is required - for example OAuth2, and it would be easier in this case to use their provided (backend) libraries for doing OAuth.
You can learn more about CORS here:
http://enable-cors.org
http://www.html5rocks.com/en/tutorials/cors
Im trying to add an image uploader on my website. I have a javascript with jcrop (the scrip is not mine, I used the one I found on the Internet); this script takes image file from computer crops it and passes to php. It starts with converting the form output to javascrip file.
var oFile = $('#image_file')[0].files[0];
This is a key line for the script, everything else is derived from oFile. I want to make it avaliable for users to upload pictures by adding a weblink (i already made possible saving image files on the localhost be posting a link); How can I open the image from my localhost with javascript and put it in the same format as oFile variable in the line above, so that my script can work with it?
You can use binary Ajax in modern browsers to fetch a resource as a file:
var oReq = new XMLHttpRequest();
oReq.open("GET", fileURLGivenByUser, true);
oReq.responseType = "blob";
oReq.onload = function(oEvent) {
var oFile = oReq.response;
processTheFileSomehow(oFile);
};
oReq.send();
This will work as long as either:
fileURLGivenByUser is on the same domain as the page running the script (e.g., your cropping script runs on foo.com and the image link is also on foo.com), or
A target image resource is served with the Access-Control-Allow-Origin: * CORS response header (e.g., your cropping script runs on foo.com, the image link is on bar.com, and bar.com serves the file with acceptable CORS headers)
So, for your user to use a localhost link, the user must be running a local Web server, and that Web server must serve its images with Access-Control-Allow-Origin: * or Access-Control-Allow-Origin: whateverdomainyouuse.com (i.e., whatever domain your cropping script runs on).
If the CORS restrictions are too restrictive (they likely are), you can use a server-side proxy on your host. For example, when you request
http://mydomain.com/proxy/http://targetdomain.com/image.png
the server does a request and responses with the contents of
http://targetdomain.com/image.png
Checking of internet connection by requesting an image does not work after the image gets cached in the browser. After one or two time, this doesn't work as the image is stored in the browser's cache so is there any solution for that? Or what do I need to check whether a connection is available or not? window.navigator.online is not reliable. so looking for the other interesting and reliable solution.
Use a cache buster querystring. The querystring forces the browser to check the servver for the new image.
yourImageObj.src = "newImage.png?time=" + new Date().getTime();
Using XMLHttpRequest object and POST protocol. POST-request does not cached. But this works only if image (or any other resource) loaded from the same domain as page (XMLHttpRequest limitation).
var xhr = new XMLHttpRequest();
xhr.open("POST", "url_for_image_file", true);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4)
if(xhr.status!==200) {
// no image loaded
alert("fail connect to server");
}
else {
alert("connection success");
}
};
xhr.send(null);
The perfect solution for checking internet connectivity is to give a ajax call to your server to the dummy page and make that dummy page's entry in the application cache manifest file in the network section so that it may not get cached in the browser, otherwise it wl take that file from browser and show you as online even if u are in offline mode.
I tried to use Twitter API to post a tweet using Javascript. Details Below
Base String
POST&http%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3DXXXXXXXXXXX%26oauth_nonce%3D9acc2f75c97622d1d2b4c4fb4124632b1273b0e0%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1305227053%26oauth_token%3D159970118-XXXXXXXXXXXXXXXXXXXXXXX%26oauth_version%3D1.0%26status%3DHello
Header
OAuth
oauth_nonce="9acc2f75c97622d1d2b4c4fb4124632b1273b0e0",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1305227053",
oauth_consumer_key="XXXXXXXXXXXXXXXXX",
oauth_token="159970118-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
oauth_signature="IWuyoPJBrfY03Hg5QJhDRtPoaDs%3D",
oauth_version="1.0"
I used POST method with body "status=Hello"
But i get a INTERNAL SERVER ERROR.. IS there any mistake on my side ?? Thanks in advance.
Javascript code used
h is the header given above
tweet="Hello"
encodeURLall is user defined which is working in all other occasions.
var xhr = new XMLHttpRequest();
xhr.open("POST","http://api.twitter.com/1/statuses/update.json", false);
xhr.setRequestHeader("Authorization",h);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 )
{
console.log("STATUS="+xhr.status);
console.log("RESPONSE="+xhr.responseText);
}
}
xhr.send("status="+encodeURLall(tweet));
}
You cannot access Twitter's site using an XMLHttpRequest, due to Same origin policy. Use JSONP instead or a server-side proxy (call your own server that redirects your request to Twitter).
BTW, what does encodeURLall() do? Shouldn't you just use encodeURIComponent?
Update: To quote Google:
Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers, but they're limited by the same origin policy. Extensions aren't so limited. An extension can talk to remote servers outside of its origin, as long as it first requests cross-origin permissions.
Please read on there to see which settings you should change in order to make this work.