Long story short, I have a structure in my angularjs app which is basically the following:
1. There is an 'authService' that is in charge of requesting access tokens, and refresh tokens.
2. There is an 'authInterceptorService' that adds the token to the header of the request, however, the tricky part is here: this service depends on the authService, for generating a new access token using a refresh token in case the access token is expired and the request is 401en, which means there will ultimately be a circular dependency, when I use the $httpProvider service to register the interceptor:
authService <- authInterceptorService <- $http <- authService
My questions is how is it possible to get around this issue when your interceptor needs to be able to issue a new access token using the refresh token and REsend the request?
One way to get around this would be use to Angular's event system. Since you are dealing with services you would probably need to broadcast the event ($emit) and listen for it ($on) on $rootScope.
For example, you can setup a listener for a 'tokenExpired' event that calls your token refresh service, which when successful fires a 'tokenRefreshed' event. When a request is 401'd you emit the tokenExpired event and register a one-time listener for the tokenRefreshed event in order to re-send the request after the refresh.
Maybe not the cleanest solution, but I've used setups like this when dealing with gnarly dependency chains and it works pretty well.
Related
How can I inject the request or the execution context in a service without the help of controller without any performance issues?
The docs make it very clear that to pass the request to a service you can use a REQUEST scoped service with #Inject(REQUEST) or you can get the request in the controller via #Req() and pass that to the service method.
There is nestjs-cls which may be helpful as well, but generally, you either pass it on or you take the performance hit for REQUEST scoping the provider.
We have a client which communicates with a server secured by OAuth2.
As implementing tokens flow we have faced a problem. When page loads, there are few components that make calls to different secured endpoints.
There is a situation when access token is expired so all requests get error and try to refresh it. So we have few asynchronous requests.
Is there an approach to deal with such situation?
Our client is written on React JS.
There are a number of solutions to this.
One solution would be to create something like a TokenService.
Before you fire any http call, you work with this service and check if you have a valid token. This is easy since when you create the token you get back information on how long the token is valid for. You store that somewhere and before you fire a call you check if you are still in the validity window. If you are then you fire the http call, if you are not then you request another and update the stored one with the new one. Once this is done then you fire your http call with the valid token.
If you don't want to manage this complexity then you could simply request a new token for every request and you're done. You use each token for one call and that's it really.
You could also use the refresh tokens functionality if you have that implemented, so if your token expires, you simply refresh it and move on
So for the past few months I have been developing the 'login functionality' of my Angular apps like this. The user logs in and if the credentials are correct, the REST API returns a token. I take that token and store it as a cookie:
$cookies.put('authorisation', data['token']);
Whenever I call the $http service, I submit the authorisation cookie as a header and it authorises the http request. Then on the controller of each view I add:
if (!$cookies.get('authorisation')) {
$location.path('/login');
}
So if the cookie doesn't exist, the user is automatically kicked to the login screen.
This has worked for me just fine up until now but I can't help but feel that it is not the 'correct' way of doing things. Could anyone shed a little light on what the best practice method for this could be? And perhaps why what I'm doing is 'wrong'?
Are you familiar with Angular $http Interceptors:
https://docs.angularjs.org/api/ng/service/$http#interceptors
You could use the request interceptor to have your authorization checked before each $http request.
If you do this you also have to integrate a custom Flag on each $http config object (e.g. skipAuthorization) in order to allow the user to perform Requests without being logged in (useful for actually logging in ;-))
#AzzyDude to your comment:
I'm using ui-router to do the navigation inside of my Angular 1.6.X Application.
You can either integrate own config-properties on the states (isGuestState) or if its a closed application such as mine, hard-coded in a $stateChange event, like this:
I am having a problem in my AngularJS and I cannot seem to find easy solution out of it.
I am using two services for user authorization with the server. The authorisation is based on two tokens: Access token and Refresh token.
Now I have one service (Auth) that takes care of the whole authorisation process and second service (Api) that takes care of communication with the server.
The way the authorisation works is that user accesses data with his Access Token. Once the token is invalitated, it will try to submit refresh token and hopefully get back new access token.
The problem is that if server responds with 401 and the token is invalidated I want to simply run Auth.authenticate(); on the background (no redirects or anything) and if successful continue with tthe new access token.
Unfortunately since Auth service is using Api service , I cannot inject Auth service back to the Api service. Is there any good way to do what I want to do from one global place(So I dont have to call the re-authorization after every single request in controller)?
Some architectural info:
Auth Service (injects Api Service)
| ---- authorisation function (uses Api Service)
Api Service
| ---- Different functions to prepare data for request
| ---- One function to send all requests
| ---- One function to handle all rejected promisses which includes detection of 401 and should include "silent" re-authorisation (AuthService.authorisation)
I really hope it doesnt sound too confusing.
I have tried interceptors, but the outcome is the same - injector loop.
The only idea I have, without changing my architecture, is if there is any way to get current active instance of the Auth service, as it is loaded anyway. But couldn't find any details on that.
Thank you!
I had a similar problem, also with my authorisation.
Sometimes re-architecting is the best solution, but I think in this case you have a good use-case for wanting the 'circular' access you are describing.
Try the following:
Inject $injector into your API service instead of your Auth service.
User $injector.get('AuthService') to get the instantiated Auth service.
I'm searching a solution but it's always the same and she's not correpond to my problem.
I have a lot of route element but for all routes with different controller I need to know if the user is authenticate or not. If yes, I have a token from an api and if no, I have a token too. So I need to have a token from an api when I load all controllers.
So I don't want to make a resolve for each "when()", I don't want to ddos the API so I search a system like this with
app.run(['Auth', function(Auth){
// Call my service & waiting his resolve
// When resolved, continue the init
}]);
So how can I make a resolve system with my "Auth" service on the run() ?
Make a service where you will have variable with status of authentication, inject this service in all controllers and in each controller call method of that service. Inside that method check variable with authentication status and only if authentication request was not yet send - send it (and set variable to status sent).