Tuesday, February 14, 2017

Secure images with angular.

Ever needed to deliver images securely? I had a usecase for delivering map tiles only if the user was authenticated - but I was using stateless authentication with Java Web Tokens (JWT). In order to use web tokens I need to place an Authentication header on each web request - easy enough. But that isnt possible to do when using a html img tag - it only allows for a url souce.

So you have two options - extend your JWT token reading service to allow it to read tokens from the url params object too (ie <img src='someurl?token=foo'> ) or instead of using the standard src attribute - use javascript to securely download the image data into a blob, and use the html5 blob data attribute for img tags.

This angular directive will do such a thing. I based my solution on this source code- except noting adding that I use an angular service "Authentication" that has a promise that will resolve only if there is valid non-expired authentication (and will refresh the token if expired).

So I only needed to modify the directive's core method to add my extra waitForAuthenticated() promise.

attrs.$observe('httpSrc', function (url) {
                    revokeObjectURL();

                    if (url && url.indexOf('data:') === 0) {
                        $scope.objectURL = url;
                    } else if (url) {
                        Authentication.waitForAuthenticated().then(function(ok){
                        $http.get(url, {
                                responseType: 'arraybuffer',
                                headers: {
                                    'accept': 'image/webp,image/*,*/*;q=0.8'
                                }
                            })
                            .then(function (response) {
                                var blob = new Blob(
                                    [response.data],
                                    {type: response.headers('Content-Type')}
                                );
                                $scope.objectURL = URL.createObjectURL(blob);
                            });
                        });
                    }
                });

The blue text is the core of the directive, pipeling the securely delivered image data into an HTML objectURL. You can attach headers easily using an injected interceptor to all $http requests.. This wont work on older browsers not supporting the objectURL standard.

No comments:

Post a Comment