Angular-JWT Authorization header exception

Problem

I've been trying to integreate Cloudinary via angular-upload into my AngularJS app. However, I have encountered this error when attempting to upload from my app:

Authorization is not allowed by Access-Control-Allow-Headers

At first I thought this was a grunt issue since I was using http-server to run the Cloudinary sample app, which uploaded successfully, but I have now realized this is more likely a result of using Auth0's angular-jwt implementation. This is attaching the Authorization header to all requests, which cloudinary does not accept. I found someone with a very similar problem here

https://github.com/DaftMonk/generator-angular-fullstack/issues/931

however, I'm having trouble figuring out how to adapt such a solution to angular-jwt. I call

$httpProvider.interceptors.push('jwtInterceptor');

in my app.config, but I want it to exclude requests to https://api.cloudinary.com/v1_1/

This is the angular-jwt distribution:

(function() {


// Create all modules and define dependencies to make sure they exist
// and are loaded in the correct order to satisfy dependency injection
// before all nested files are concatenated by Grunt

// Modules
angular.module('angular-jwt',
    [
        'angular-jwt.interceptor',
        'angular-jwt.jwt'
    ]);

 angular.module('angular-jwt.interceptor', [])
  .provider('jwtInterceptor', function() {

    this.urlParam = null;
    this.authHeader = 'Authorization';
    this.authPrefix = 'Bearer ';
    this.tokenGetter = function() {
      return null;
    }

    var config = this;

    this.$get = ["$q", "$injector", "$rootScope", function ($q, $injector, $rootScope) {
      return {
        request: function (request) {
          if (request.skipAuthorization) {
            return request;
          }

          if (config.urlParam) {
            request.params = request.params || {};
            // Already has the token in the url itself
            if (request.params[config.urlParam]) {
              return request;
            }
          } else {
            request.headers = request.headers || {};
            // Already has an Authorization header
            if (request.headers[config.authHeader]) {
              return request;
            }
          }

          var tokenPromise = $q.when($injector.invoke(config.tokenGetter, this, {
            config: request
          }));

          return tokenPromise.then(function(token) {
            if (token) {
              if (config.urlParam) {
                request.params[config.urlParam] = token;
              } else {
                request.headers[config.authHeader] = config.authPrefix + token;
              }
            }
            return request;
          });
        },
        responseError: function (response) {
          // handle the case where the user is not authenticated
          if (response.status === 401) {
            $rootScope.$broadcast('unauthenticated', response);
          }
          return $q.reject(response);
        }
      };
    }];
  });

 angular.module('angular-jwt.jwt', [])
  .service('jwtHelper', function() {

    this.urlBase64Decode = function(str) {
      var output = str.replace(/-/g, '+').replace(/_/g, '/');
      switch (output.length % 4) {
        case 0: { break; }
        case 2: { output += '=='; break; }
        case 3: { output += '='; break; }
        default: {
          throw 'Illegal base64url string!';
        }
      }
      return decodeURIComponent(escape(window.atob(output))); //polifyll https://github.com/davidchambers/Base64.js
    }


    this.decodeToken = function(token) {
      var parts = token.split('.');

      if (parts.length !== 3) {
        throw new Error('JWT must have 3 parts');
      }

      var decoded = this.urlBase64Decode(parts[1]);
      if (!decoded) {
        throw new Error('Cannot decode the token');
      }

      return JSON.parse(decoded);
    }

    this.getTokenExpirationDate = function(token) {
      var decoded;
      decoded = this.decodeToken(token);

      if(typeof decoded.exp === "undefined") {
        return null;
      }

      var d = new Date(0); // The 0 here is the key, which sets the date to the epoch
      d.setUTCSeconds(decoded.exp);

      return d;
    };

    this.isTokenExpired = function(token, offsetSeconds) {
      var d = this.getTokenExpirationDate(token);
      offsetSeconds = offsetSeconds || 0;
      if (d === null) {
        return false;
      }

      // Token expired?
      return !(d.valueOf() > (new Date().valueOf() + (offsetSeconds * 1000)));
    };
  });

}());

Help?

Problem courtesy of: cassiusclay

Solution

jwtInterceptor checks the request for a skipAuthorization flag, and does not send the Authorization header if it was set to true.

Build your $http call like

$http({
    url: 'https://api.cloudinary.com/v1_1/',
    skipAuthorization: true,
    method: 'POST',
    // ... etc
}).then(successCallback, errorCallback);

- More at angular-jwt Docs

Solution courtesy of: Khaled Shaaban

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.