Loading images with JWT Authorization

Or how to enhance native HTML

If you have been doing JS + HTML for more than a few days, chances are you are familiar with the img tag. The concept is easy — put an img tag in your markup, provide a src attribute with a URL of an image, and boom — you have a picture on your page. For example, if we have a picture at https://somewhere.com/image.png , we can do this:

So far it is nothing fancy, but what if we don’t want just anyone having access to this image? Of course, from the API point of view it won’t be hard to implement some basic authentication. Say, JWT Authorization is very popular nowadays. But here comes another problem — with JWT we need a special string — a token, to be passed alongside the request to the server, to help the server recognize the user that makes the request. Of course, if we were using an HttpClient instance to get the image, it would be no big deal — we would just add the header on the request with the options parameter. But how do we force the img tag to request the image via an HttpClient instance?

The answer is pipes.

Here is what we are going to do:

Write a pipe that accepts an image url and performs the HTTP request while putting on the Authorization header, Transform the blob response to a base64 string so it can be passed to the src attribute, Put the base64 string into a Promise , so that it can be passed to the async pipe in its turn, Call the pipe inside an src attribute, Optionally specify a fallback image if something goes wrong, Optionally create a component that handles all of this logic

Let’s start with the basic pipe:

So here we:

Get the token from our local service, Put it inside the headers , Call for the image using those headers, Specify responseType: 'blob' to tell Angular we are loading a binary file here

Note the usage of toPromise and async / await .

Of course, this is only half of the job — we still need to convert the binary to a base64 string. Here comes the FileReader . (I am going to provide only the implementation of the transform method)

We just wrapped the file reading process in a Promise, so we can use it combined with the async pipe:

If we open the Network tab in Chrome, we will see the request for the image and find the headers we look for:

If you look closely though, you will notice we did not do any error handling in our transform method. What if the image just does not exist? What if there is a server error? Regardless of the nature of the error, we can provide a fallback image:

We just wrap the HTTP request in a try / catch block, and return a fallback image url in case of an error. Notice that we did not wrap the fallback image url string a Promise, because as the method is already async , it is done automatically.

Optionally we can also return different fallback images for different error scenarios (one for 404 , one for Server Error , and so on) with a switch statement, but this is out of the scope of this article.

Finally, we can write a component to replace all our img tags throughout our app with the Authorized version of it:

And then use it just like this:

CAUTION: One thing you need to keep in mind is CORS: your image serving server should be configured in a way that it accepts XHR calls for images from the domain your Angular app is running on, or you will run into CORS error. Also, you will have to provide absolute urls to the custom pipe, otherwise it will make requests to the Angular app’s domain itself.

Conclusion

As we see, it is entirely possible to replace a native HTML element with a wrapper around it to perform custom logic. Pipes come in handy in this process too.

Follow me on Medium and Twitter for more on Angular, Rxjs, React, and Javascript in general.