First of all, I am not really sure if I need to ask this here or on (for example) StackExchange ? Fell free to redirect me.
I am developing a website which has 2 parts :
A connected part, for admins.
An unconnected part, for customers.
And I am struggling with a best practice to have in my case.
The administrator pages call API endpoints which are protected with JWT. They can GET, POST, PUT, and DELETE data. The GET repository methods do not use EF's AsNoTracking() (for non-.NET devs, it allows to avoid tracking any changes on the database entities), as the admins could want to update the data.
The customers on the other hand, won't have the possibility to update data. It's only readonly, and will stay readonly in the future. As they are not connected and do not have a token, they can't call the same API endpoints than the admins.
I have multiple ideas to handle this but I do not know what is the best practice regarding REST.
Create, in the same controller, other GET endpoints, with no token auth, that calls another repository method that uses AsNoTracking() to avoid any changes (even if it should not happen) on the entity, in addition to the (minor) performance improvement it causes.
Create a separate controller, with a different route : api/Client/Controller/Action.
(My least prefered option), remove token auth on admin's GET endpoints and conditionally add AsNoTracking() based on if the caller is a customer or an admin.
Anything else that would be better ?
I feel like I do not have an option that is 'perfect' regarding code duplication or single responsibility principle.
Thanks
After further investigations, the best option would be solution 2.
By creating a new controller, dedicated to customers, we can :
Avoid mixing both JWT protected and non protected endpoints.
Make a separation between administrators and customers, from both the endpoints route POV but also in the project architecture.
Avoid having a big controller in which all endpoints would not be used based on if the caller is an administrator or a customer.
Related
The question in short
What would be the correct way to handle JWT authentication for a user
who is accessing data from microservice A but where microservice A requires data from Microservice B.
The Setup
I am using Auth0 to issue and handle authentication and authorisation.
I have two microservices set up. The user is logged in on the front end and needs to load tenant-based accounting information.
Microservice A is an aggregate service that communicates to multiple different services in order to provide a standardized response for different types of data types.
Microservice B is queried by Microservice A in order to retrieve vehicle information owned by the user.
Which solution would be the correct approach?
Solution A:
The token that was issued to the user when he logged in will be used by MS A to communicate with MS B. MS A is essentially forwarding the token provided by the user.
Solution B:
MS A has its own JWT which has super admin rights to access any resource from MS B. MS A will use this token when accessing resources from MS B and MS A will take responsibility for ensuring that resources not accessible to the user are not returned in the aggregated dataset.
In solution B you put a lot of responsibility on MS A to properly handle the data. In my opinion it's just asking for trouble, eventually someone will manage to call MS A in such a way to get some more data than they can access. So I would go with solution A, or a variant of it. There are a couple ways how tokens can be shared between services - passing the same token, embedding tokens or exchanging tokens. I have written an article about Token Sharing a while back, you can have a look at it.
I think it depends - both options are OK depending on the scenario.
Here are a few things to consider.
Does microservice B do any resource owner authorization e.g. using the sub claim from the users JWT? If so it might be easier to just pass through the user access token. Note: generally I only use data inferred from the JWT for authZ logic. If you need something like the resource owner ID as part of the business logic, you should explicitly include this in the request payload, so that the service can also be consumed by back-end services using M2M tokens.
With Auth0, there's a cost for machine MUAs (monthly unique authentications). This is separate to the cost for user MUAs. For an enterprise account the default is 1000 M2M MUAs. Increasing this number is pretty cheap, but still something to consider. In general you should configure your M2M tokens to have a longer expiration (e.g. 1-2 days) and use token caching. Generally an in-memory cache will suffice, but if you're building serverless apps (e.g. AWS Lambda, Azure Function Apps, etc) you'll probably need a distributed cache. All this is extra work, complexity, and potentially cost (e.g. for distributed cache) for M2M tokens.
There's additional network request (to Auth0) for M2M authentications. This is mitigated through the use of token caching, but something to consider as well.
Is microservice B going to be publicly accessible? If yes, you may have some security considerations as users will be able to call microservice B directly with their access tokens (obtained legitimately), but they might be able to tamper with requests in ways you weren't intending.
The company that I work for use a mix of the 2 approaches you mentioned (which generally depend on the scenario). We have some helper utils for things like token caching etc., which make both approaches easy enough, but if you're going to use M2M tokens you'll probably have a bit of additional work up-front.
One last thing to mention; when implementing 'transitive' services like microservice B, I think it's good to ensure the service is consumable by both user and machine tokens. You're authZ policies might allow for one or the other (or both), but at least you'll have the flexibility to change if/when needed.
I'm developing an web API and I'm trying to follow the principles of REST. I'm now at the stage of creating the endpoint where a user can delete its own account. I have also implemented JWT functionality where the JWT is valid for 1 day.
I want to add an extra layer of security when the user is deleting its own account. My idea is that the user have to provide its current password in the body of the delete request. I did some googling which pointed to having a body in a delete request is a bad idea because some entities does not support it, e.g. the Angular HttpClient, some web services might strip the body, etc.
I know GitHub have a similar functionality when deleting a repository, you have to provide your password. I like this feature because it prevents unauthorized persons from spoofing the JWT on critical operations, right?
What are your recommendations
Proceed with using DELETE and deal with the potential problems that might come along with this approach?
Instead use POST, PUT or PATCH even though it would look semantically wrong?
Other solution?
I would not recommend to use other http methods like put or patch if you really want to delete it and not only disable it. That would not be intuitive for the API user and could lead to misunderstandings.
One solution for your use case is to introduce an additional resource (e. g. deletionRequest) to request (but not immediately execute) the deletion of the profile with a post call. Then you could do the actual deletion with a delay (preferably longer than the token life span). You could then inform the user via email about the deletion, so the real user has the chance to revoke the deletion. If the user does not react in time, the deletion is executed.
The problem to face lies in the design of a RESTful API that can manage requests from multiple roles in an RBAC-based solution.
Currently we have different resources that can be accessed from different users, which can have one or more roles grouped according to their privileges.
The API we're trying to define must be as clear as possible to the client but without the overhead of adding additional metadata to the URL that could damage and even conflict with the REST practices and definitions. Therefore, we must avoid at all costs include information about the roles inside the URL. The plan is to use JWT tokens that carry in their payloads the info needed to know which permissions has the user making the request.
Having raised our current situation, let's provide an example and state the problem to solve:
Suppose we have * financiers * and * providers * as users with some roles who both want to access ** attentions ** (our resource). Should we add before the resource ** attentions ** information about the * user * whose trying to access the resource?
The endpoints in that case should be defined (as an example) as:
https://example.com/api/v1/financiers/:id/attentions
https://example.com/api/v1/providers/:id/attentions
This way we're attempting to inform the respective controllers that we want the ** attentions ** for that specific role / user which are, in some way, a sub-resource of them.
On the other hand, we could simply implement a much simpler endpoint as follows:
https://example.com/api/v1/attentions
The logic about which attentions return from the database should be now implemented in an unique method that must handle this two roles (and potentially new ones that could come up in the following features). All the information needed must be obtained from the payload from the token, exposing a much more generic API and freeing the web client from the responsibility of which endpoint call depending on the role.
I want to highlight that the attentions are managed in a Microservices Architecture and, hence, the logic to retrieve them is gathered in a single service. The cost of the API Gateway to route the two (and potentially more) of the endpoints from the first solution is a variable not to discard in our specific situation.
Having exposed our current situation:
Which we'll be the best approach to handle this issue?
Is there another alternative not contemplated that could ease the role management and provide a clean API to expose to the client?
In the second solution, is correct to return only the attentions accessible to that specific user based on the roles that it has? Isn't it counterintuitive to access an endpoint and only get some of the resources from that collection (and not all) based on its role?
I hope that someone could clarify the approach we're taking as there are little and none literature that I've found regarding this issue.
There there are multiple solutions for such kind of filtration, and developer have to select one depending on given situation.
As per my experience I can list following.
Structure
When data can't be accessed directly and developer has to use a relation (i.e a table JOIN). In that case URL have to include both the main and sub entities. Before going with this approach a good check is to ask, if the same URL can be used with POST ?
Example
If we have to fetch list of roles assigned to a specific user or want to assign additional roles then we can use
GET users/:uid/roles
POST users/:uid/roles
Security
With Multi-tenant systems where each user can have his/her private resources, i.e other users are prohibited from accessing those resources. Developer should save tenancy information and to filter the resources according to current authentication, without bothering client or requiring any additional info in URL
Example
Phone album of the user
GET photos
POST photos
Search
If it is not security or structure related but client still want to filter the result set depending on his scenario. then developer should use query-string for the filtration.
Example
Client have to fetch messages from his/her inbox or outbox or want messages which are not yet read. or he/she want to search his/her inbox
GET messages?folder=inbox
GET messages?folder=inbox&status=unread
GET messages?search=nasir
I'm trying to figure out best or common practices for API design.
My concern is basically this:
PUT /users/:id
In my view this endpoint could by used for a wide array of functions.
I would use it to change the user name or profile, but what about ex, resetting a password?
From a "model" point of view, that could be flag, a property of the user, so it would "work" to send a modification.
But I would expect more something like
POST /users/:id/reset_password
But that means that almost for each modification I could create a different endpoint according to the meaning of the modification, i.e
POST /users/:id/enable
POST /users/:id/birthday
...
or even
GET /user/:id/birthday
compared to simply
GET /users/:id
So basically I don't understand when to stop using a single POST/GET and creating instead different endpoints.
It looks to me as a simple matter of choice, I just want to know if there is some standard way of doing this or some guideline. After reading and looking at example I'm still not really sure.
Disclaimer: In a lot of cases, people ask about REST when what they really want is an HTTP compliant RPC design with pretty URLs. In what follows, I'm answering about REST.
In my view this endpoint could by used for a wide array of functions. I would use it to change the user name or profile, but what about ex, resetting a password?
Sure, why not?
I don't understand when to stop using a single POST/GET and creating instead different endpoints.
A really good starting point is Jim Webber's talk Domain Driven Design for RESTful systems.
First key idea - your resources are not your domain model entities. Your REST API is really a facade in front of your domain model, which supports the illusion that you are just a website.
So your resources are analogous to documents that represent information. The URI identifies the document.
Second key idea - that URI is used by clients to cache representations of the resource, so that we don't need to send requests back to the server all the time. Instead, we have built into HTTP a bunch of standard ways for communicating caching meta data from the server to the client.
Critical to that is the rule for cache invalidation: a successful unsafe request invalidates previously cached representations of the same resource (ie, the same URI).
So the general rule is, if the client is going to do something that will modify a resource they have already cached, then we want the modification request to go to that same URI.
Your REST API is a facade to make your domain model look like a web site. So if we think about how we might build a web site to do the same thing, it can give us insights to how we arrange our resources.
So to borrow your example, we might have a web page representation of the user. If we were going to allow the client to modify that page, then we might think through a bunch of use cases (enable, change birthday, change name, reset password). For each of these supported cases, we would have a link to a task-specific form. Each of those forms would have fields allowing the client to describe the change, and a url in the form action to decide where the form gets submitted.
Since what the client is trying to achieve is to modify the profile page itself, we would have each of those forms submit back to the profile page URI, so that the client would know to invalidate the previously cached representations if the request were successful.
So your resource identifiers might look like:
/users/:id
/users/:id/forms/enable
/users/:id/forms/changeName
/users/:id/forms/changeBirthday
/users/:id/forms/resetPassword
Where each of the forms submits its information to /users/:id.
That does mean, in your implementation, you are probably going to end up with a lot of different requests routed to the same handler, and so you may need to disambiguate them there.
My task is to implement a resource server(RS) for IdentityServer4(IS4). The RS should fetch data from a database and send the necessary information as a json object back to the caller (client). This is needed because we have to return complex objects.
I already setup IS4 succesfully and its already running in Docker for testing purpose. I also setup the needed database.
My understanding of the flow would be, the user requests data from the RS sending the access-token, the RS then validates the token, checking if the caller is allowed to access the api using the IS4, if everything is okay the RS returns the data to the caller.
My problem is, as I'm new to this subject, how would I implement a RS? Do I create an API which is added as a scope to the user? Or is there a RS already implemented in IS4?
So yes you'll need to write your own API to serve your own resources, IdentityServer will only manage your identities for you (as well as handling external logins if that's what you need). I'd recommend going to the IdentityServer docs and working through the quick starts in order as shown below:
This will give you a good start but you'll then need to go away and research APIs more generally, there's a tonne of good info online about building (RESTful) APIs. You may find it useful to sign up to something like PluralSight and work through a couple of their courses, they're often very good.
One other thing to bear in mind is that IdentityServer is for identity, in other words Authentication and not specifically for Authorisation so you may need to add something for this. You can of course use a users identity for authorisation purposes but in most cases you'll probably need to augment the info you store about their identity to authorise them for access. See this link for more info around this topic.