I am building a FeathersJS app with authentication and authorization.
I handle the authorization manually with before hooks on almost every route besides the "/authentication" route because of course you want to leave this route unprotected so everyone is able to authenticate/login.
My problem is that when I call the /authentication route it also calls the /users route which is protected. Of course this is a problem which often occurs because this route is called by multiple other routes but I filter these calls in the authorization hook with
if(context.params.providers) {...}
When I call the /authentication route the hook is called with the /users route and a provider is set, which should not be like that if I am right.
Is there a way to filter this /authentication route?
The current authentication code assumes you can call the users get with an external provider (mostly to make sure the user returned to the client has any after hooks applied to filter/prune sensitive data.
Note that the call feathers makes to get the user with the provider set also includes the user in the params, so you can use that user context to make authorization decisions (e.g. allow a user to retrieve his/her own user record).
https://github.com/feathersjs/feathers/blob/master/packages/authentication/src/jwt.ts#L103
Related
I am exposing REST API's via an API Gateway so the requests go
Client => API Gateway => Back-end.
My back-end REST API's need to know about 2 users
1: Target User (on some requests)
the API needs this data for its action eg: groups/{abc}/add-user needs to know which user to add to a group
2: Calling User (on every request):
the API needs to check that this user is allowed to perform the action eg: only a group admin may add another user to the group.
I don't want other developers to get confused when looking \ adding to my API's so I want to create a convention. Is it a good idea to add the calling user ID as a header on every request?
eg: "user-context": "12345"
Before everyone screams "INSECURE!!!!", I should add some info to put your minds at ease
The calling user is allowed to know their user-id. It's not a problem
The target user is not identified by their real user-ID but by an obfuscated ID
The calling-user-id is actually passed in a signed JWT to my API Gateway. The API-Gateway validates the JWT, takes the calling-user-id and adds it to the back-end request. What i'm really asking here is whether the API-Gateway should put the calling-user-id in the header (eg: "user context": "12345") or the query string /myapi/?calling-user-id=12345
I've tried both approaches and they both work. I'm wanting to know which approach makes the most sense to other developers.
I am managing performing a login and the login state using Vuex. It is a standard procedure of:
User submits their login details on a form
The form dispatches a Vuex action to make an axios API call to a Node/Express endpoint /api/login with the credentials
The response from the API if successful will send back the user's data which is stored in the state.user object through a setUser mutation. A flag of state.user.isLoggedIn is also set to true.
A JWT access token is sent to the user's browser and stored in a secure cookie to use over and over again until it expires. If it expires, a refresh token is used to generate a new JWT access token.
The site's header displays the user's login information .e.g name
The above all works as expected. However if the user refreshes their browser, then Vuex state gets emptied and the site header no longer shows the user information. To overcome this I stored state.user into localStorage in the browser as persisted data and repopulate the Vuex store using the data in localStorage on page refresh. If the user logs out, the localStorage is cleared.
There are many routes that require checking if the user is logged in. I cannot rely on localStorage because it can be manipulated by the user. If the user deletes their cookies which contains a JWT, then localStorage is not being emptied and the site header still displays their log-in information. Therefore I need to do an API call on almost every page to check if the user is logged in and if not then to delete the localStorage as well.
My question is:
Where do I perform a log-in check every time a page/view is accessed? Is it whenever the Vue app is mounted or within vue-router using the beforeEach navigation guard?
If I use beforeEach in vue-router, is it going to crash the site by making an API call to /api/login every time a user changes route? Is it normal practice to do this on every route?
Are there any other alternative patterns to keeping track of if the user is logged in or not?
Application decisions like this tend to be subjective because every application is different, with different requirements and different architectures. It sounds like this is a single page application, so I'll go from there.
First, the fact that your JWT is set up and working is great - that can be a lot of hard work, so be proud that you made it that far.
If your application has certain pages that are accessible without first being logged in (like a login page, or an access denied page, etc.), then you have to consider that in the design as well. In this case, a beforeEach route guard is the perfect solution to keep a route from loading or to catch those not-logged-in users before they attempt to request content that will likely just give them an error.
You probably shouldn't have to make an API call to the server each time the user navigates to a new page. That would probably be a little slow. Because your application uses JWT, complete with refresh tokens, you should be able to rely on them, so that if a user is logged in, they will continue to be logged in until they close their browser and walk away.
This is why you should not use localStorage. When a tab closes or even after a reboot, the user will still appear to be logged in. Instead of using localStorage, use sessionStorage - Helpful MDN link.
Now, the login event to retrieve the user object should only happen once per browser tab, but stay active during the visit.
I wonder why you don't just request a new user object from the server when the browser is refreshed. It's not strange to force a re-check to the server for a full page load. Doing that would mean you wouldn't have to use anything outside of Vuex to store the user's state
Next, is there a way to check the validity of their JWT during the navigation event? Depending on the way you handle the JWT, you may have access to it, and can possibly decode it (like through the oidc-client-js library), and that way determine for yourself if the token is expired. However, if the token is expired, your token refresh system may just refresh it and not tell you about it.
You can also watch your HTTP requests and look out for 401 or 403 responses (however your back-end handles logged-out users), and direct the user back to the login screen if you see one of those. You can use Axios' global interceptors to catch them, or do it yourself if you centralized the location from where Axios is called.
Overall, you're on your way, and clearly have a good grasp on this. Great progress so far, having done probably 90% of the heavy lifting already.
I use JWT token in my project and i have an Api route that i want to remove token that send from user.
I searched a lot and many people say to put my route in $except array in VerifyCsrfToken class , but it does not work.
I want this solution because if user send request with token, the result that returned is differ from result that returned without token.
///edited
I have one route without middleware and guard, in Product model i wrote a global scope that affect on is_active column.
public function apply(Builder $builder, Model $model)
{
if (Auth::guard('manager')->check()) {
return $builder;
}
if (Auth::guard('customer')->check()) {
return $builder->where('is_active', '=',true);
}
return $builder->where('is_active', '=',true);
}
if manager use this route for products, all products returned.
i want the user's role have no effect on output.
in other word i want to remove token from some api routes
I am not sure I fully understand your question.
But isn't it possible to just adequately add one layer of middleware and do your filtering there?
So you could check if the user has a token or not and react accordingly (like forwarding the user on a specific route).
In case that may help, you can find a few middleware related videos here explaining how it works.
VerifyCsrToken is for CSRF and it's different with JWT token.
In this situation you have 2 different solution:
When your user is sending JWT token, It means your user was authenticated, and you can get user's object and send proper response.
You could make 2 different controller, and two routes, one of them for without token and another one with token, And according to user request, make your proper response.
I have created a simple WebAPI in Visual Studio C# to act as my backend to Angular.
Users can register via the Angular frontend and passed to a controller in the WebAPI to register that user in the backend DB (MSSql). All fine.
I am using token authentication from Angular to my API and using claims and roles to verify the user is logged in and has access to the requested controller.
How, as an Admin, can I disable another user so they are instantly locked out?
An example would be: A rogue user starts abusing the Angular application and I need to lock them down instantly and not to wait until their token expires and they are required to login again.
I could do a check in each and every controller to lookup the user in the DB and check their status and if I have set their status to "locked-out" then return say a 403 forbidden status from the controller but this seems a lot to lookup the user for each DB request they make.
Is there a "dot-net" way of doing it? I would love to be able, as the admin, to instantiate the said user, change their claim value for "status" to "locked-out" and I simply check their claim when making api requests but I can't see a way of changing another users claims.
Any ideas?
Thank you.
Expanding on my comment above, we have a handler in our pipeline that handles Authorization. We do look at that Authorization header and parse it but all of the controllers rely on the already-parsed value that we hang in the Properties collection. That way all AuthZ/AuthN occurs in this handler and whatever the handler sets in the Properties collection is what all of the application sees.
In your case the handler would need to be able to check whatever throttle or lockout you are using and replace the actual claims received with your "user is locked out" claims instead.
When a user changes a dropdown, I need to make an ajax call to an endpoint, that grabs the data and return it as a JSON.
I can do the event stuff with Vue, to make the request, but how do I guarantee that Vue is the requestor?
I can't really put an API key or something in the JS as that can be viewed through source. Someone could also watch the network tab in chrome and replay the requests to retrieve the data.
Unless you want to ask people to login first, there is no way you can do this. There is a HTTP header you can look for that most libraries add for Ajax requests, but that can be faked as well.
You cannot hide any information from the request you are making. It's the server side on which you can make your code strong. To prevent fake request you can use CSRF token, you need to also validate if the user is logged in, you can check session etc. before you send the result to the client.