Determine if bearer token has expired or is just authorized - angularjs

My angular application is making use of bearer tokens as outlined in the article series http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/. I have followed the forked example to seamlessly refresh tokens when the access token has expired (via 401 http code).
My question is how can I determine if the bearer token is expired or just plain unauthorized based on the role determined?
For example, my web api method has the attribute [Authorize(Roles="Admin")]. When I make a call to that, I get back my 401 error, which is expected. However, when my access token expires and I make another web api method call, it also returns a 401 error. Heres my responseError handler in my interceptor:
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('/dashboard');
deferred.reject(rejection);
});
} else {
deferred.reject(rejection);
}
return deferred.promise;
}
I was playing around with different things but basically, I'd like to refresh my token and resend my request when the access token has expired; however, I don't want to refresh my token if it truly is a denied request due to the role specified.
Any thoughts?

As noted in my response to Cory Silva's comment, the Web API Authorize attribute will always return 401 unauthorized for both authentication AND authorization.
See article and thread below:
http://leastprivilege.com/2014/10/02/401-vs-403/
Why does AuthorizeAttribute redirect to the login page for authentication and authorization failures?
It looks like there are two options:
When I store the token retrieved from my authorization server in localStorage, I also store the token's expiration. In the interceptor responseError function, I compare the stored token expiration with the current datetime. If it's determined to be expired, refresh the token and resend the request.
responseError: function (rejection) {
var deferred = q.defer();
if (rejection.status === 401) {
var tokenExpired = false;
var authData = localStorage.get('authorizationData');
if (authData) {
tokenExpired = moment().isAfter(authData.expiration);
}
if (tokenExpired) {
var authService = auth;//$injector.get('authService');
authService.refreshToken().then(function (response) {
_retryHttpRequest(rejection.config, deferred);
}, function () {
authService.logOut();
$state.go('error');
deferred.reject(rejection);
});
}
else {
$state.go('error');
deferred.reject(rejection);
}
} else {
$state.go('error');
deferred.reject(rejection);
}
return deferred.promise;
}
Use the accepted answer in the stackoverflow thread I referenced above and create my own AuthorizeAttribute to determine token expiration vs. unauthorized access.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
if (actionContext.RequestContext.Principal.Identity.IsAuthenticated)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
}
else
{
base.HandleUnauthorizedRequest(actionContext);
}
}
}
I think I'm going to use option 2 so that the error codes a little clearer to the client.

Related

How can I refresh a user's session using JWT token

I'm fairly new to Angular and I'm trying to implement a mechanism for keeping active users logged in as long as they're active.
I have a token endpoint that issues a JWT token to a user
{
"access_token": "base64encodedandsignedstring",
"token_type": "bearer",
"expires_in": 299,
"refresh_token": "f87ae3bee04b4ca39af6f22a198274df",
"as:client_id": "mysite",
"userName": "me#email.com",
".issued": "Wed, 19 Apr 2017 20:15:58 GMT",
".expires": "Wed, 19 Apr 2017 20:20:58 GMT"
}
And another call that takes the refresh_token and uses it to generate a new access token. From the Api standpoint this should enable me to pass in the refresh_token and generate a new JWT with a new expires date.
I'm not 100% sure on how to wire up the Angular side to support this, my login function:
var _login = function (LoginData) {
var data = "grant_type=password&username=" + LoginData.UserName + "&password=" + LoginData.Password + "&client_id=4TierWeb";
var deferred = $q.defer();
$http.post(serviceBase + 'authToken', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).then(function (response) {
localStorageService.set('authorizationData', { token: response.data.access_token, userName: LoginData.userName, refreshToken: response.data.refresh_token, useRefreshTokens: true });
_authentication.isAuth = true;
_authentication.userName = LoginData.UserName;
deferred.resolve(response);
}, function (err, status) {
_logOut();
deferred.reject(err);
});
return deferred.promise;
};
My refresh function:
var _refreshToken = function () {
var deferred = $q.defer();
var authData = localStorageService.get('authorizationData');
if (authData) {
if (authData.useRefreshTokens) {
var data = "grant_type=refresh_token&refresh_token=" + authData.refreshToken + "&client_id=4TierWeb";
localStorageService.remove('authorizationData');
$http.post(serviceBase + 'authToken', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).then(function (response) {
localStorageService.set('authorizationData', { token: response.data.access_token, userName: response.data.userName, refreshToken: response.data.refresh_token, useRefreshTokens: true });
// response.headers.Authorization = 'Bearer ' + response.token;
deferred.resolve(response);
}, function (err, status) {
_logOut();
deferred.reject(err);
});
}
}
return deferred.promise;
};
And my interceptor:
app.factory('authInterceptorService', ['$q', '$location', 'localStorageService', function ($q, $location, localStorageService) {
var authInterceptorServiceFactory = {
request: function (config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
},
responseError: function (error) {
if (error.status === 401) {
$location.path('/login');
}
return $q.reject(error);
}
};
return authInterceptorServiceFactory;
}]);
My interceptor works great without the refresh mechanism in place as above, but when I add the refresh mechanism:
authService.RefreshToken();
config.headers.Authorization = 'Bearer ' + authData.token;
I'm able to pull down a new JWT but the next line doesn't seem to be working correctly anymore, I'm getting 401 on my landing page and there is no bearer token in the payload, what am I missing here?
Updated Interceptor:
app.factory('authInterceptorService',['$q', '$location', 'localStorageService', '$injector', function($q, $location, localStorageService, $injector) {
return {
request: function(config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
},
responseError: function(rejection) {
//var promise = $q.reject(rejection);
if (rejection.status === 401) {
var authService = $injector.get('authService');
// refresh the token
authService.refreshToken().then(function() {
// retry the request
var $http = $injector.get('$http');
return $http(rejection.config);
});
}
return $q.reject(rejection);
}
};
}
]);
You need to wait for the refresh_token request to complete obtaining a new access token and then use the response to issue a new request.
Like: authService.refreshToken().then(doRequest())
Lets suppose that you have 2 functions inside authService:
function getAccessToken() { ...get access token like in login()... } - returning Promise
function refreshToken() { ...existing logic... } - returning Promise
Let us say that you will use jwt_decode(jwt) to decode the JWT token.
I think you can go two ways with your implementation:
1st way: get the token and immediately subscribe in order to refresh when expired
function getAccessToken() {
...
return $http(...)
.then(function(response) {
// ...correct credentials logic...
if(authService.refreshTimeout) {
$window.clearTimeout(authService.refreshTimeout);
}
// decode JWT token
const access_token_jwt_data = jwt_decode(response.data.access_token);
// myOffset is an offset you choose so you can refresh the token before expiry
const expirationDate = new Date(access_token_jwt_data * 1000 - myOffset);
// refresh the token when expired
authService.refreshTimeout = $window.setTimeout(function() {
authService.refreshToken();
});
return response.data;
})
.catch(function(error) {
// ...invalid credentials logic...
return $q.reject(error);
});
}
NOTE: You can use window instead of $window. I don't think that you actually need a new digest cycle at that moment. A new digest will be launched when $http request completes successfully or not.
NOTE: This means that you need to take care also of the case when you reload the page. Thus re-enabling the refresh timeout. So you can reuse the logic within getAccessToken() for subscribing to expiry date but this time you get the token from the localStorage. This means that you can refactor this logic into a new function called something like function subscribeToTokenExpiry(accessToken). So you can call this function in your authService constructor if there is an access token in your localStorage.
2nd way: refresh the token in your HTTP interceptor after receiving an error code from server.
You can refresh your token if your interceptor receives an error that match a token expiry case. This depends strongly on your back-end implementation so you may receive HTTP 401 or 400 or anything else and some custom error message or code. So you need to check with your back-end. Also check if they are consistent in returning the HTTP statuses and error codes. Some implementation details might change over time and framework developers might advice users to not rely on that specific implementation because is only for internal use. In that case you can leave only the HTTP status and omit the code, as you will have better chances of having the same in the future. But ask your back-end or the ones that created the framework.
NOTE: regarding Spring OAuth2 back-end implementation, find the details at the end of this answer.
Getting back to your code, your interceptor should look like:
app.factory('authInterceptorService',
['$q', '$location', 'localStorageService', 'authService', '$injector',
function ($q, $location, localStorageService, authService, $injector) {
var authInterceptorServiceFactory = {
request: function (config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
},
responseError: function (response) {
let promise = $q.reject(response);
if (response.status === 401
&& response.data
&& response.data.error === 'invalid_token') {
// refresh the token
promise = authService.refreshToken().then(function () {
// retry the request
const $http = $injector.get('$http');
return $http(response.config);
});
}
return promise.catch(function () {
$location.path('/login');
return $q.reject(response);
});
}
};
return authInterceptorServiceFactory;
}]);
Spring Security OAuth2 back-end related:
I add this section for those curious about Spring Authorization Server implementation as Spring is a very popular framework in the Java world.
1) Expiry date
Regarding the expiry date, this is expressed in seconds. You will find the "exp" key inside your access_token and refresh_token after you JWT decode the string.
This is in seconds because you add the JwtAccessTokenConverter which uses DefaultAccessTokenConverter that does:
if (token.getExpiration() != null) {
response.put(EXP, token.getExpiration().getTime() / 1000);
}
JwtAccessTokenConverter is added when the Authorization Server is being configured:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// ...
endpoints.accessTokenConverter(jwtAccessTokenConverter)
// ...
}
}
2) Access token expired response
You might need to handle one or both of HTTP 400 and HTTP 401 statuses and rely on { "error": "invalid_token" }. But this depends strongly on how the back-end was implemented using Spring.
See the explanations bellow:
Regarding, the resource server configuration (the one to which we send the request to in order to get the resource we want), the flow is as follows:
OAuth2AuthenticationProcessingFilter servlet filter to get access token from request
OAuth2AuthenticationManager to parse token string
DefaultTokenServices to obtain the access token object.
OAuth2AuthenticationProcessingFilter try catch will delegate the exceptions to OAuth2AuthenticationEntryPoint which creates the response for the exception.
DefaultTokenServices is a ResourceServerTokenServices implementation.
There are two possible such implementations, one is this DefaultTokenServices and the other is RemoteTokenServices.
If we use DefaultTokenServices then the token will be checked on the resource server. This means that the resource server has knowledge of the key that signed the token in order to check the token validity. This approach means distributing the key to all parties that want such behavior.
If we use RemoteTokenServices then the token will be checked against /oauth/check_token endpoint handled by CheckTokenEndpoint.
On expiry CheckTokenEndpoint will create an InvalidTokenException with HTTP 400, that will converted by OAuth2ExceptionJackson2Serializer into HTTP 400 with data { "error": "invalid_token", "error_description": "Token has expired" }.
On the other hand DefaultTokenServices will create also a InvalidTokenException exception but with other message and without overriding the HTTP status thus being HTTP 401 in the end. So this will become HTTP 401 with data { "error": "invalid_token", "error_description": "Access token expired: myTokenValue" }.
Again this, HTTP 400 or HTTP 401, happens because InvalidTokenException is thrown in both cases DefaultTokenServices throws without overriding getHttpErrorCode() which is 401 but CheckTokenEndpoint overrides it with 400.
Note: I added a Github Issue in order to check if this behavior, 400 vs 401, is correct.
I've used this interceptor at a couple of occasions without any problems.
You can set it up to refresh the token silently and only throw an error (and navigate to the login screen) if the refresh fails. Hope this helps
Is it secure to use a refresh token in an Angular application ? I'am not sure...
The OIDC implicit flow (which is the flow used for SPA or mobile apps), there is no refresh token involved.

Ionic : no content / white screen using interceptors

I successfully managed to use interceptors (AngularJs ) in my Ionic application. Previous post .
While it is working perfectly well in the browser using "ionic serve".
There is no content loaded in the header title and content block ( "ion-content" ) using "ionic run android" (either emulating on genymotion or on my own phone). See screenshot below.
I'm pretty sure it comes from the interceptors i'm using, because before that, the app was working on any platforms. Also, as soon as i remove the interceptors it is working again. Here the code.
Note that i'm checking which url is called so i don't go into a circular dependency or checking useless url, only the calls to my api go through.
app.config(function($httpProvider){
$httpProvider.interceptors.push(['$location', '$injector', '$q', function($location, $injector, $q){
return {
'request' : function(config){
// intercept request
// carefull includes might not work while emulating
// use instead indexOf for that case
if(!config.url.includes('/oauth/v2/token') && config.url.includes('/api')){
// inject the service manually
var OauthService = $injector.get('OauthService');
var access_token = OauthService.token();
config.url = config.url+'?access_token='+access_token.key;
}
return config;
}
}
}]);
});
Any ideas what could give this error? (By the way console is showing no errors on browser).
UPDATE :
OauthService.js :
app.factory('OauthService', function($http, $localStorage) {
return {
token : function(){
// Store actual token
access_token = $localStorage.getObject('access_token');
// Store actual identity
identity_token = $localStorage.getObject('identity_token');
// IF no user logged
if(isObjectEmpty(identity_token)){
// IF access_token does NOT exist OR will expires soon
if( isObjectEmpty(access_token) || Date.now() > (access_token.expires_at - (600*1000)) ){
// Create an anonymous access_token
return $http
.get(domain+'/oauth/v2/token?client_id='+public_id+'&client_secret='+secret+'&grant_type=client_credentials')
.then(function (response) {
$localStorage.setObject('access_token', {
key: response.data.access_token,
type: 'anonymous',
expires_at: Date.now()+(response.data.expires_in*1000)
});
return response.data.access_token;
});
}
}
// IF user is logged
else{
// IF access_token does NOT exist OR will expires soon OR is anonymous
if( isObjectEmpty(access_token) || Date.now() > (access_token.expires_at - (600*1000)) || access_token.type == 'anonymous' ){
// Create an access_token with an identity
return $http
.get(domain+'/oauth/v2/token?client_id='+public_id+'&client_secret='+secret+'&api_key='+identity_token+'&grant_type=http://oauth2.dev/grants/api_key')
.then(function (response) {
$localStorage.setObject('access_token', {
key: response.data.access_token,
type: 'identity',
expires_at: Date.now()+(response.data.expires_in*1000)
});
return response.data.access_token;
});
}
}
return access_token.key;
}
};
})
Did you install cordova whitelist plugin ?
cordova plugin add cordova-plugin-whitelist
or if you want to save the reference to your config.xml file:
cordova plugin add cordova-plugin-whitelist --save
If you don't have that your device won't be able to access external resources.
You can find more info here.
UPDATE:
I've checked your previous answer.
The idea of the interceptor is to intercept calls to an external service insert some action in the pipeline.
I would change your interceptor:
$httpProvider.interceptors.push(['$location', '$injector', '$q', '$localStorage', function($location, $injector, $q, $localStorage){
return {
'request' : function(config) {
config.headers = config.headers || {};
access_token = $localStorage.getObject('access_token');
if (access_token) {
config.headers.Authorization = 'Bearer ' + access_token;
}
}
'response' : function(response){
if (response.status === 401) {
logger.debug("Response 401");
}
return response || $q.when(response);
}
'responseError' : function(rejection){
if (rejection.status === 401) {
var OauthService = $injector.get('OauthService');
var access_token = OauthService.token();
if (access_token === null)
{
return $q.reject(rejection);
}
// Append your access token to the previous request and re-submits.
rejection.config.headers['Authorization'] = 'Bearer ' + access_token;
return $injector.get('$http')(rejection.config);
}
// This is necessary to make a `responseError` interceptor a no-op.
return $q.reject(rejection);
}
}
}]);
If you look at the interceptor above it manages all the requests to an external resource (REST api) and appends a bearer token to the authorization header if needed.
The response does not do much as it is only there for logging purposes.
responseError is the place where you should intercept and check if your token as expired, fetch a new one and resubmit the request.
We check if the user is not authorized to the request:
if (rejection.status === 401) { ... }
If not we request a new access token. I guess your OauthService does that.
If we have a new access token:
var access_token = OauthService.token();
we can, again, append the access token to the request header:
rejection.config.headers['Authorization'] = 'Bearer ' + access_token;
and resubmit the previous request:
return $injector.get('$http')(rejection.config);
If you want to find out more about interceptors you can read these blogs.

Angular interceptor reload the view after get refresh token

I have an implementation of JWT and when the token expires im get 401 and then i do this:
send request to get new token.
2.resend what the user request before.
Now before this the data isnt display in the page because the token is invalid, but now after the token is valid and i resend the request the user made, how i can refresh the state or the controller to auto show the data that the user ask before?
'responseError': function(rejection) {
if (rejection.status === 401) {
var $http = $injector.get('$http');
AuthService.getRefreshToken().then(function(res) {
//here im sending back the original user request again
//and now when the data is coming back because the token is valid now i want display that to the user
return $http(rejection.config);
});
}
}
I had the same problem and i use this module:
angular-http-auth
After you add this to your app, just add this code:
'responseError': function(rejection) {
if (rejection.status === 401) {
AuthService.getRefreshToken().then(function(res) {
// make sure you are inject the authService
authService.loginConfirmed();
});
}
}
And thats all, your code will continue to work.

implementing refresh-tokens with angular and express-jwt

I want to implement the Sliding expiration concept with json web tokens using angular, nodejs and express-jwt. I'm a little confused on how to do this, and am struggling to find any example of refresh tokens or and other material relating to sessions with these technologies/frameworks.
A few options I was thinking of were
Generating a new token with each request after the initial login
Keeping track of issued token on the server side along
But I'm honestly not sure, please help
I managed to implement this scenario.
What I've done...
On the server:
-Enable an API endpoint for signin. This endpoint will respond with the Json Web Token in the header. The client side has to catch it (with $http interceptors) and save it (I use local storage). The client will also manage the refreshed tokens sent by the server.
-On every request to the server configure a middleware in express to validate the token. At first I tried express-jwt module but jsonwebtoken was the right one for me.
For specific routes you may want to disable the middleware. In this case signin and signout.
var jwtCheck = auth.verifyJWT;
jwtCheck.unless = unless;
app.use('/api', jwtCheck.unless({path: [
'/api/auth/signin',
'/api/auth/signout'
]}));
-The middleware verifyJWT always responds with a token in the header. If the token needs to be refreshed a refreshed function is called.
jwtLib is my own library where the code lives to create, refresh and fetch jwt tokens.
function(req, res, next) {
var newToken,
token = jwtLib.fetch(req.headers);
if(token) {
jwt.verify(token, config.jwt.secret, {
secret: config.jwt.secret
}, function(err, decoded) {
if(err) {
return res.status(401).send({
message: 'User token is not valid'
});
}
//Refresh: If the token needs to be refreshed gets the new refreshed token
newToken = jwtLib.refreshToken(decoded);
if(newToken) {
// Set the JWT refreshed token in http header
res.set('Authorization', 'Bearer ' + newToken);
next();
} else {
res.set('Authorization', 'Bearer ' + token);
next();
}
});
} else {
return res.status(401).send({
message: 'User token is not present'
});
}
};
-The refresh function (jwtLib). As argument needs a decoded token, see above that jsonwebtoken resolve a decoded when call to jwt.verify().
If you create during signin a token with an expiration of 4 hours and have a refresh expiration of 1 h (1 * 60 * 60 = 3600 secs) that means that the token will be refreshed if the user has been inactive for 3 hours or more, but not for more than 4 hours, because the verify process would fail in this case (1 hour window of refreshing). This avoids generating a new token on each request, only if the token will expire in this time window.
module.exports.refreshToken = function(decoded) {
var token_exp,
now,
newToken;
token_exp = decoded.exp;
now = moment().unix().valueOf();
if((token_exp - now) < config.jwt.TOKEN_REFRESH_EXPIRATION) {
newToken = this.createToken(decoded.user);
if(newToken) {
return newToken;
}
} else {
return null;
}
};
On the client (Angularjs):
-Enable a client side for login. This calls the server endpoint. I use Http Basic Authentication encoded with base64.
You can use base64 angular module to encode the email:password
Note that on success I do not store the token on the localStorage or Cookie. This will be managed by the http Interceptor.
//Base64 encode Basic Authorization (email:password)
$http.defaults.headers.common.Authorization = 'Basic ' + base64.encode(credentials.email + ':' + credentials.password);
return $http.post('/api/auth/signin', {skipAuthorization: true});
-Configure the http interceptors to send the token to the server on every request and store the token on the response. If a refreshed token is received this one must be stored.
// Config HTTP Interceptors
angular.module('auth').config(['$httpProvider',
function($httpProvider) {
// Set the httpProvider interceptor
$httpProvider.interceptors.push(['$q', '$location', 'localStorageService', 'jwtHelper', '$injector',
function($q, $location, localStorageService, jwtHelper, $injector) {
return {
request: function(config) {
var token = localStorageService.get('authToken');
config.headers = config.headers || {};
if (token && !jwtHelper.isTokenExpired(token)) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
requestError: function(rejection) {
return $q.reject(rejection);
},
response: function(response) {
//JWT Token: If the token is a valid JWT token, new or refreshed, save it in the localStorage
var Authentication = $injector.get('Authentication'),
storagedToken = localStorageService.get('authToken'),
receivedToken = response.headers('Authorization');
if(receivedToken) {
receivedToken = Authentication.fetchJwt(receivedToken);
}
if(receivedToken && !jwtHelper.isTokenExpired(receivedToken) && (storagedToken !== receivedToken)) {
//Save Auth token to local storage
localStorageService.set('authToken', receivedToken);
}
return response;
},
responseError: function(rejection) {
var Authentication = $injector.get('Authentication');
switch (rejection.status) {
case 401:
// Deauthenticate the global user
Authentication.signout();
break;
case 403:
// Add unauthorized behaviour
break;
}
return $q.reject(rejection);
}
};
}
]);
}
]);

Handle Angular 401 responses

I have simple api and a authorization point
when i request to api i get a 401 if the token is invalid (token loses validity past five minutes).
i know i can intercept 401 for example with
app.factory("HttpErrorInterceptorModule", ["$q", "$rootScope", "$location",
function($q, $rootScope, $location) {
var success = function(response) {
// pass through
return response;
},
error = function(response) {
if(response.status === 401) {
// dostuff
}
return $q.reject(response);
};
return function(httpPromise) {
return httpPromise.then(success, error);
};
}
]).config(["$httpProvider",
function($httpProvider) {
$httpProvider.responseInterceptors.push("HttpErrorInterceptorModule");
}
]);
but i want capture and queue the request and show a login form if is success then change the token (it's a header) and execute request again
You can use $httpInterceptor in slightly another way. If you want to redirect user after login to page where user actually failed you need to cache failed request in some service and then redirect user somewhere after login (I beleive in logic connected to your login).
But you may need to have some test endpoint to protect your controllers from unrestricted access, you might want to use resolve https://thinkster.io/egghead/resolve/
So in this case you will receive error connected with restricted access to proctedted endpoint but not to your page.
To solve this problem I used marker param (or header) to find out where I should redirect user after login.
Here is example of your httpInterceptor.
angular.factory('httpInterceptor', function ($q, $rootScope, $log, someService) {
return {
request: function (config) {
return config || $q.when(config)
},
response: function (response) {
return response || $q.when(response);
},
responseError: function (response) {
if (response.status === 401) {
//here I preserve login page
someService
.setRestrictedPageBeforeLogin(
extractPreservedInfoAboutPage(response)
)
$rootScope.$broadcast('error')
}
return $q.reject(response);
}
};
})
.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
});
angular-http-auth module provides a service that intercepts requests and queques them to re-send them later once a user logs in.
This service fires also these events below, so you could listen to them and decide what to show on screen
event:auth-loginRequired
event:auth-loginCancelled
event:aut-loginConfirmed
Look at the code. It has just a few lines of code
https://github.com/witoldsz/angular-http-auth

Resources