How to authorize different roles on a .Net 5 OAuth API - asp.net-core

I have an IdentityServer4 application, a client application and a .Net 5 API. I want the client application to be able to talk to my API on the users behalf with an access token. Some users should be able to do admin requests while others should only be able to do normal user tasks.
I believe I need to add two scopes for these, api.admin and api.normal.
First question is where would I add these scopes in identityserver? Does the client request both scopes and just gets back whatever IS decides is right for that user?
Secondly, how do I validate what scopes are in the access token on my API. Method 1 should only be used if the access token contains the api.admin scope for eg.
Thanks!

First, scopes are something you typically hard-code in your client and it does not "vary" between users. It main purpose is to indicate what the "client" application want to have access to, not the user.
So you only need only one scope like "api".
Then you have different roles or claims in the access-token that describe what the authenticated user have access to.
You then use the authorization middleware in the API to determine what the user actually have access to.
Like what the picture below shows:

There is no reason that different scopes could not be requested by the client based on the user interacting with the client or even environmental based criteria.
As some quick example, a USER that has Authenticated to a Client Application that determines the user is a "Preferred Customer" vs a visitor might be granted scope to allow reading "Preferred Content".
The client then requests a "preferredcontent" scope for the "Preferred Customer" and not for the visitor.
And of course the Authorization Server may reject the scopes requested for any reason.

Related

How do I use Auth0 roles to modify my API's behavior, rather than simply deny authorization?

My express.js backend has an endpoint which returns a list of what data the user is authorized to view. There are Auth0 roles corresponding to which segments of this data any given user is allowed to read. A user may have any number of these roles. However, when I tried to add role-based permissions to this endpoint, I realized that the Auth0 recommended middleware express-jwt-authz perhaps doesn't do what I intend: it simply authorizes/rejects based on the roles in the JWT. This endpoint only requires a user's session authorization, not the user's roles.
I want the endpoint to change its responses based on which Auth0 roles are associated with a user. The only solution I can think of is adding a row to my own database (which is not connected with Auth0) where I keep track of each user by the JWT sub property, and manage their roles/permissions from my backend. However, this seems like it would split roles between Auth0 and my application's database, and furthermore feels one step closer to rolling my own authentication system, which I do not want right now. Is there a way I can do this with Auth0 and express.js?
I was able to work around this by selecting "Add Permissions in the Access Token" in Auth0 in Applications > APIs > [my API] > Settings. Then I could view the permissions passed into req.user.permissions on my backend, and process them how I wanted there.

Is JWT right for me?

I've done a fair amount of research on the many different ways to authenticate and authorize users who use my frontend application to access my REST API. I've built a system that uses OAuth2 and JWT and need a sanity check since I'm working on this alone.
For a bit of background, my frontend is built using Vue.js and my API is built using Django with Django Rest Framework. My team is already planning on concurrently developing the mobile and desktop versions of this app which both would require authentication and authorization as well.
To keep things brief, I'll omit the alternative solutions I have and just talk about the most controversial one.
Right now, OAuth2 (my authorization server) grants users a JWT token using ROPC when they provide their email and password to my frontend client. I should note that my API (my resource server) and authorization server live on the same machine.
My application allows users to essentially signup using different plans (for example a free plan and a paid plan). When a user signs up for a free plan, I need the frontend application to not only disable certain features and elements in the UI, but also I need the authorization server and or resource server to limit what that user is allowed to query based on their plan.
The idea is when a user signs up or logs in, my authorization server will get the associated user record from the database and create a valid JWT with a claim attached that states the user's plan and maybe some other non-personal information. Then once signed it sends it off to the user where the frontend can enable/disable parts of the UI... etc. Hence, if a user logs in on mobile, we can customize the UI based on the same claim sent by the JWT.
My issue is that I don't know if this is a good way to go about it. It seems that everyone I've asked in my circle is split on using JWT or not. Those apposed mostly raise security issues, but, when from what I understand, many of the JWT security pitfalls are well documented and can be avoided just using some commonsense as with any other session/token-based authentication. I'm starting to get analysis paralysis. Please help.
CLASSIFICATION
I would say this is really an API Authorization question, as opposed to an OAuth question:
The role of the Authorization Server and tokens is really just to prove the user's identity
Product specific logic comes after the user logs in and is generally best handled in your app
MY PREFERENCES
Here is how I would handle it:
Save the plan type to your product data when the user signs up
After login, look up the user from the access token
Then look up the user's plan type from your product data
Produce a Claims / Principal object in your API containing both
Enforce business rules based on the plan type claim
I would aim for a Claims object something like this:
class ApiClaims {
// The user id in the access token
userId: string;
// The email
email: string;
// The plan type
planType: string;
// Other claims from the token
// Other claims from product data, eg user roles
}
RESOURCES
If interested in this approach, these blog posts of mine may be of interest:
User Data Management
API Authorization
JWT?
You need some kind of API credential that is sent in HTTPS messages and is web and mobile friendly, so I would use JWTs. You could follow the same pattern with any API credential though.
It depends on what you are trying to protect of course, but JWT bearer tokens are an industry standard. Since you control both the client and the authorization server, you can implement it however you like.
I would look into changing Resource Owner Password Credentials flow to authorization code flow. It will enable you to use social authentication providers like Google or Facebook to sign in users (while still maintaining plan info in your own service). Chances are that people trust those companies more to keep their credentials safe than your company, and it allows you to benefit from any authentication features (MFA) those companies implement.
Also, if you want the clients to read the contents of the token, you should use OpenID Connect id_tokens, as those are guarenteed to be in JWT format.

API - allow users access to only data they created

This is an API related question that applies to the APIs that I'm working on and would like to know the standard way of doing this.
say a user1 has created accounts so he can access it by
GET /accounts
but when he accesses transactions for a particular account
GET /accounts/acct1/transactions
how would this API know that the acct1 actually belongs to that user1 and is not the case where user2 is accessing user1's accounts.
This api is accessed via a Mobile app using Oauth 2.0 tokens. So while the access token control the access to API endpoints, how do we control access to only specific user's data at that endpoint. (using scopes?)
I've been looking at Spotify's apis and they seem to be doing this via v1/me end point.. Still reading...
I'm a noob at this and it looks to me that this should be documented somewhere in a standard manner in some RFC, but I couldn't find it and would appreciate direction
Can you provide more details on your use case? Why are you using OAuth?
It sounds like you need an authentication protocol - i.e. a protocol to let your server know who is accessing a particular API.
To quote the OAuth website:
OAuth 2.0 is not an authentication protocol
OAuth's main use-case is letting one application perform operations on behalf of a user of another application.
As an example, if your server wants to post a message on Facebook on behalf of a user, you will use OAuth to obtain a token from Facebook which lets you post messages on behalf of the user. Note that, in the most general case, your application does not know which user is represented by the token. Indeed, the user may not even be a (registered) user of your application - they only have to be a user of Facebook.
Practically speaking, you often can use the token you have to query Facebook for the identity of the user. So your server would extract the OAuth token from the request headers and use it to issue a query to Facebook's Graph API to obtain the user ID.
Note that the user is a Facebook user rather than a user of your app, so you will need to somehow map the Facebook user ID to your own users and permission system - i.e. check your database to ensure that the user has permissions to do what they asked to do.
This is the mechanism that is typically used when using OAuth like an authentication protocol (which, as quoted above, it is not).
I should add that if your app obtains an OAuth token and passes it to your server for the purposes of authentication, then this flow is not 100% secure, as discussed for example here, so make sure you do proper risk analysis for your case. In a nutshell, a determined attacker can theoretically impersonate your app and obtain tokens representing other users.

IdentityServer 4 and scope specific user settings

I plan to use IdentityServer 4 on ASP.NET Core with ASP.NET Identity as the data store. This is the first time I use a central authentication/authorization and I am wondering how to solve the following question:
Assume I have users with claims like name, role etc. and a Web API (scope) that allows these users access to measured values from hardware devices. IdentityServer will allow me to authenticate known users but now I need an access control that knows which users may access which device data.
Where do I store this information? Since it is specific to the scope I guess it should not be stored in the IdentityServers store. On the other hand, if I store it in the scopes own database I somehow need to connect it to the users defined in the IdentityServers store. Should I define user IDs that are unique to all scopes and IdentityServer?
You will need to correlate the User Ids that IdentiyServer returns with users defined in the scope's database.
I believe that there is a User table and a UserLogin table where you could track the different logins for each of your users.
Then, in the scope's database, you can then specify which users have access to what device data.
This is a bad idea and will probably lead you down a road that you should not.
This means that your client application requesting the scopes will need to know which user has access to which scopes even before requesting a token from your IDP (otherwise your token request will not work). Rather model these as user claims. Then on your WebApi you can do normal claim based authorization.

Scope and Claims (again!)

I'd like to ask a question to confirm my understanding of how to use Scopes and Claims (roles). Let's say I have a User (User A with read only rights i.e. suitable read only role), a Windows Service (Client A with read only access), an MVC site (Client B with full access), and a Web API. I want the Web API to be accessed by Users and Clients with full access and read only access.
I create two Scopes "sampleApi.full and "sampleApi.read_only"
I create two Roles "full_access" and "read_only"
I configure the Web API with RequiredScopes = new[]{"sampleApi.full", "sampleApi.read_only"}
When Client A connects to the Web API, it passes an Access Token containing Scope "sampleApi.read_only" and I can use [ScopeAuthorize("sampleApi.full)] or ScopeAuthorize("sampleApi.full, sampleApi.read_only")] on my Classes and Methods to fine tune accessibility. No problem.
However, when User A logs in, then he/she "inherits" the Scopes of Client B. So the Access Token contains "sampleApi.full", "sampleApi.read_only", and Role "read_only".
Now I have a problem at the WebApi in that I need to act differently when being called by a User. In that case I ignore the Scopes and use his/her Roles and the User gets "read_only" access which is what I want.
That being correct, it no longer makes sense to use the ScopeAuthorize attribute, and I need a custom hybrid attribute that does something along the lines:
If Caller is a User
- then use Roles to determine accessibility
Else
- use Scopes to determine accessibility
or have I completely misunderstood?
Scopes model what a client (not user) is allowed to access. They are manifest as claims in the token. The user's claims are also in the token. Authorization in the resource will be based on a combination of what the client is allowed to do and what the user is allowed to do. That's it.