TypeScript interceptor in AngularJS - angularjs

I'm having problems setting up a request interceptor in AngularJS using TypeScript
The following snippet works, not working variant is commented out. No matter what I inject in the constructor the local variables are undefined in the request method.
module Services
{
export class AuthInterceptor
{
public static Factory(TokenService: Services.ITokenService)
{
return new AuthInterceptor(TokenService);
}
constructor(private TokenService: Services.ITokenService)
{
this.request = (config: ng.IRequestConfig) =>
{
config.headers = config.headers || {};
if(this.TokenService.IsAuthorised())
config.headers.Authorization = 'Bearer ' + this.TokenService.Token;
return config;
};
}
public request: (config: ng.IRequestConfig)=>ng.IRequestConfig;
/* THIS IS NOT WORKING
public request(config)
{
// this.TokenService is undefined here as well as $window or $q which I tried to inject
config.headers = config.headers || {};
if(this.TokenService.Token != "")
config.headers.Authorization = 'Bearer ' + this.TokenService.Token;
return config;
}
*/
}
}
angular.module("Services")
.config(($httpProvider: ng.IHttpProvider)=>
{
$httpProvider.interceptors.push(Services.AuthInterceptor.Factory);
});

It is because of the wrong this. Solution:
public request = (config) =>
{
// this.TokenService is undefined here as well as $window or $q which I tried to inject
config.headers = config.headers || {};
if(this.TokenService.Token != "")
config.headers.Authorization = 'Bearer ' + this.TokenService.Token;
return config;
}
To understand why you need this : https://www.youtube.com/watch?v=tvocUcbCupA&hd=1

Related

How to override header Token with AngularJS

I have problem to override header token with AngularJS becauase already set with AuthInterceptor.
app.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if (localStorage.getItem("token")!=='') {
config.headers.Authorization = 'Bearer ' + localStorage.getItem("token");
}
return config;
},
};
});
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
I would access another third party URL where using another Token,but always failed, because Token back to current Token in localStorage. I have used TransformRequest, but not work too, what is best practice to solve the problem?
You could check that the URL in the intercepted request is a URL that you want to pass an authorization token. For instance, if the URL to your own API always starts with https://api.myapp.com, you could do it like this:
app.factory('authInterceptor', function ($rootScope, $q, $window) {
var urlForAuthorization = 'https://api.myapp.com';
return {
request: function (config) {
config.headers = config.headers || {};
if (config.url.startsWith(urlForAuthorization)
&& localStorage.getItem("token") !== '') {
config.headers.Authorization = 'Bearer ' + localStorage.getItem("token");
}
return config;
}
};
});

How to conditionally bypass request interceptor in AngularJs

I'm having trouble bypassing my auth interceptor:
request: function (config) {
if (config.headers["NoAuth2"] !== null) return config;
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
} else {
var authService = $injector.get('authService');
authService.logOut();
$location.path('/login');
}
return config;
}
Ideally, when the headers have NoAuth2 present in it's collection, I'd like to bypass adding the token and just return the config via something like:
$http.post(config.url + "pubrequest", request, { headers : {NoAuth2 : 1}})
From my controller.
However, I can't seem to get it to work despite several SOE examples on it, any ideas?

How to skip angularjs interceptor for an HTTP request?

I have an angularjs app, in which I have an interceptor that adds the authorization token to the header of each request.
However, somewhere in the application I need to use and external API where the interceptor ruins it, because it adds this authorization header which is not acceptable by this external API provider. How can I make angularjs HTTP skip the interceptor, only on this one specific case?
The interceptor code is below:
app.factory('authInterceptorService', ['$q', '$injector', '$location', 'localStorageService', function ($q, $injector, $location, localStorageService) {
var authInterceptorServiceFactory = {};
var $http;
var _request = function (config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
//console.log("token: " + authData.token.substring(0, 10));
//console.log("user: " + authData.userName);
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
var _responseError = function (rejection) {
var deferred = $q.defer();
if (rejection.status === 401) {
var authService = $injector.get('authService');
authService.refreshToken().then(function (response) {
_retryHttpRequest(rejection.config, deferred);
}, function () {
authService.logOut();
$location.path('/login');
deferred.reject(rejection);
});
} else {
deferred.reject(rejection);
}
return deferred.promise;
}
var _retryHttpRequest = function (config, deferred) {
console.log('retrying');
$http = $http || $injector.get('$http');
$http(config).then(function (response) {
deferred.resolve(response);
//console.log("success:" +response);
}, function (response) {
deferred.reject(response);
//console.log("error:" + response);
});
}
authInterceptorServiceFactory.request = _request;
authInterceptorServiceFactory.responseError = _responseError;
return authInterceptorServiceFactory;
}]);
Easy
$http.get("url" , {noAuth : true}).then(success(),error());
In the Interceptor
var _request = function (config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData && !config.noAuth) {
//console.log("token: " + authData.token.substring(0, 10));
//console.log("user: " + authData.userName);
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
Simple. Change this line
if (authData) {
to
if (authData && !config.headers.hasOwnProperty('Authorization')) {
And for any request where you do not want the header applied, use
$http({
headers { Authorization: null },
// and the rest
})
Write like this :-
var _request = function (config) {
if (config.url.indexOf('yourExternalApiUrl') > -1) {
return config;
} else {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
//console.log("token: " + authData.token.substring(0, 10));
//console.log("user: " + authData.userName);
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
}
For more details you can see : http://www.codemosquitoes.com/2016/06/using-angularjs-interceptors-with-http.html
If you are looking for the auth0 interceptor:
export class InterceptorService implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
var allow = ['/assets/i18n/de.json', '/assets/i18n/en.json'];
if (allow.includes(req.url)) {
const noToken = req.clone();
return next.handle(noToken);
}
return this.auth.getTokenSilently$().pipe(
mergeMap(token => {
const tokenReq = req.clone({
setHeaders: { Authorization: `Bearer ${token}` }
});
return next.handle(tokenReq);
}),
catchError(err => throwError(err))
);
}
}

angular multiple interceptors in app.config

in my angular app, I want to add informations to all calls to an external API.
To do so, I use interceptors that I call from within app.config.
app.config(['$httpProvider', ... , function($httpProvider, ...){
$httpProvider.interceptors.push('globalInterceptorService');
$httpProvider.interceptors.push('authInterceptorService');
}]);
It works fine when I only use one interceptor. But when I use 2 of them (as in the example above) the action of one gets overridden by the other.
Any idea about how to deal with multiple interceptors? Maybe is it recommended to have only 1? Any help is much appreciate.
Interceptor 1 :
function globalInterceptorService ($q, localStorageService) {
var service = {};
var _request = function (config) {
config.headers = config.headers || {};
var AreaId = localStorageService.get('AreaId');
if (AreaId) {
config.headers.AreaId = 'AreaId ' + AreaId;
}
return config;
};
service.request = _request;
return service;
}
Interceptor 2 :
function authInterceptorService ($q, $location, localStorageService) {
var service = {};
var _request = function (config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
};
service.request = _request;
return service;
}
I think you should push the function, not its string name.
function globalInterceptorService($q, localStorageService){...}
$httpProvider.interceptors.push(globalInterceptorService);
example: http://jsfiddle.net/aartek/tbhobfbu
Or
function globalInterceptorService($q, localStorageService){...}
$provide.factory('globalInterceptorService',globalInterceptorService)
$httpProvider.interceptors.push('globalInterceptorService');
example: http://jsfiddle.net/aartek/tbhobfbu/2/
It's well described in the documentation

Should I use Service or Factory for my $http interceptor

I need to implement an interceptor for the $http service. I have tried 2 implementations using a factory and a service, they both work OK. this is the implementation in type script:
Service:
export class AuthInterceptorService {
private _authService:Services.IAuthService;
static $inject = ['$q', '$location', '$injector'];
constructor(private $q: ng.IQService, private $location: ng.ILocationService, private $injector: ng.auto.IInjectorService) {
}
private getAuthService = (): Services.IAuthService=> {
if (this._authService == null) {
this._authService = this.$injector.get('authService');
}
return this._authService;
}
public request = (config: ng.IRequestConfig) => {
config.headers = config.headers || {};
var authData = this.getAuthService().authData;
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
public responseError = (rejection)=> {
if (rejection.status === 401) {
this.getAuthService().logOut();
}
return this.$q.reject(rejection);
}
}
In app init:
.service('authInterceptorService', Services.AuthInterceptorService)
Factory:
export function AuthInterceptorFactory($q: ng.IQService, $injector: ng.auto.IInjectorService) {
return {
request: (config: ng.IRequestConfig)=> {
config.headers = config.headers || {};
var authData = $injector.get('authService').authData;
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
},
responseError: (rejection)=> {
if (rejection.status === 401) {
$injector.get('authService').logOut();
}
return $q.reject(rejection);
}
};
}
In app init:
.factory('authInterceptorFactory', ['$q', '$injector', Services.AuthInterceptorFactory])
and then on configuration of the interceptor:
.config(['$httpProvider', ($httpProvider:ng.IHttpProvider) => {
$httpProvider.interceptors.push('authInterceptorxxxxx');
}])
As you can see I am using the service location pattern to inject a dependency (using $injector), this is to avoid a circular dependency since the injected service has a dependency on $http.
As I said they both work, I prefer the Service version as it allows me to cache the injection of the dependent service 'authService', in the factory flavour it gets resolved and injected all the time on every request. Is there any problems in using the Service implementation? in Angular docs they refer you should use a factory.
There is nothing wrong with using a service for an HttpInterceptor. Angular will simply call injector.get to resolve it, so using a service is fine.
From source $injector.get(interceptorFactory) https://github.com/angular/angular.js/blob/6f19a6fd33ab72d3908e3418fba47ee8e1598fa6/src/ng/http.js#L207-L210:
forEach(interceptorFactories, function(interceptorFactory) {
reversedInterceptors.unshift(isString(interceptorFactory)
? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
});

Resources