Sep 18, 2020

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0f27ee1d-3341-4c29-a048-d00334b3e46c/Untitled.png

Image illustration: https://webhostinggeeks.com/guides/privacy/

I had the problem to show the image in html. But, at this time I should authenticate the user who can do it. So, if someone have the link, they can't get the image — or scrape it anyway. I'll share this to remind me in the future how I was handled this 🤣

In easy way, we can append the link of image with authorization token. So, this is how it looks like:

<img src="<https://image-link.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ>..." />

Of course, not that easy. How if someone know this and stole the token of someone else to authenticated himself and access the entire endpoints with it?


The goal of this is: make a secure link for <img> tag, so only certain authenticated users can see it.

Keep the Bucket Private

First, whatever the services you choose to store the attachments for your app, make sure that is private and only can be accessed by the key ID and secret. We can use AWS S3, Google Storage, or etc. then save the secrets in env of back-end.

Now, at this point, I assume we had the endpoints that securely — with header authorization, to upload and get the attachments from the server side.

Save the Authorization Token in Cookie

To make it easier, in front-end you must save the authorization token in cookie of the user's browser. Anyway, this is the modern way to store the token in the client side.

And actually, we can store to the cookie by the response header of the request token endpoint. This is the sample code if you using express.js for the server side:

function (req, res) => {
	...
	return res.cookie('token', token, { expires: ... }).send(token)
}

Make a Proxy in Front-end

After all of it we keep should build the URL for the <img> tag in HTML. The strategy is to add an endpoint on the front-end side to return the image obtained from the server with the authorization token in the cookie.

Okay, I know only code can make us understand each other, right? 😂 So, here's what code example I mean:

app.get('/image', async (req, res) => {
  const { authorization } = req.cookies
	const { url } = req.query
  const image = await axios.get(url, {
    headers: { authorization },
    responseType: 'stream'
  })
  res.writeHead(200, image.headers)
  res.end(image.data)
})