I have a token-authenticated API that serves images. The specific images to be served are dynamically selected based on user action (think a file browser). I'm trying to figure out how to populate HTML images with authenticated requests.
Putting the token in the URI is a bad idea because it can easily be leaked.
Cookies won't work because the API needs to be safe to access from different origins.
What I've tried
First thing I tried was fetching the images manually (setting the token in a header), then setting the src
attributes using URL.createObjectURL
. This works, but performance is severely degraded from all the CORS preflight requests.
My next idea was to circumvent CORS by using POST requests with the content type set to text/plain
, although in reality it's JSON with the token included. This gets rid of CORS by making it a "Simple Request". But this also opens up a security hole that has to be plugged on the server by ensuring POST+text/plain
requests never perform any mutating actions (either that or cookies must not be used at all).
That got rid of the preflights, but now I have another performance problem: the browser doesn't cache POST requests, for good reasons.
So is there a simple way to achieve authenticated GET requests that are performant (cached and no CORS)?
Note the easy solution would be if the spec included an idempotent request that could use the body for the query. But obviously that would complicated caching since you have to take the body into account.
(More complex) ideas I haven't tried yet
Pre-signed URLs would likely work, but would greatly increase the complexity of my backend. The way I've designed it doesn't fit well with this paradigm.
Another idea I had was that the token could be used as a shared secret to sign each request (probably the URI). The signature would be included in the URI query. This exposes access to the specific resources requested, but not to the token itself, while tying the validity of the request URLs to the life of the token. Security-wise this seems equivalent to presigned URLs, but I'm no security expert and there are likely subtleties I'm missing.