Current situation: I have an application with 3 WebAPI projects (let's say API A, B, C). Each has token-based auth (based on OAuthAuthorizationServerProvider). There are 3 user types (let's say Type 1, 2, 3). Each user type is stored in the separate database table;
- "API A" used by mobile clients ("Type 1" users)
- "API B" used partly by mobile clients ("Type 1" users), partly by web client (angular application, "Type 2" users)
- "API C" used by web client ("Type 3" users)
Also,
- "Type 1" users can get token from "API A" and exchange it to another token from "API B" in order to get access to "API B" resources (some controllers in "API B" used by "Type 1" users, others - by "Type 2" users)
- "Type 2" users have 2-step authorization
- They use login and password to get a token with "restricted access" to a single controller in order to choose some value from it
- Using the previous token and chosen value they exchange it to "full access" token
I'm planning to migrate from the current authorization scheme to IdentityServer4. So, I have a few questions:
Main question:
- How to authenticate 3 different user types in 3 different database tables by a single endpoint (server/connect/token) with single IdentityServer4 instance?
Additional questions:
- How can I implement 2-step authorization for "Type 2" users?
- What can you advise in my situation?
Thanks!
For IdentityServer there is only one type of user that needs to be authenticated. So all users should be moved to the same table (how to migrate is another question). If moving the users to one table is an issue, then IdentityServer may not be the right tool to implement security. Though it is possible to maintain seperate tables by implementing a custom user store. Two factor authentication can be enabled per user. You can use extension grants to implement custom grants.
The whole purpose of security is to protect your resources: the api's. In IdentityServer the resource name is a logical name for the functionality that can be split in several scopes, where a scope is a certain functionality.
Api1
can be the resource with multiple scopes (e.g.Api1.Read
andApi1.Write
) or simplyApi1
. ButApi1
,Api2
andApi3
can also be part of theApi
resource whereApi1
,Api2
andApi3
are in fact scopes. In your caseApi1
could be the resource withApi1
as scope.To make it possible for the user to access a resource you'll need a client application, though you can have many clients that can access the same resource. In order to support the different types of clients, there are multiple grant types that can be chosen from.
IdentityServer allows you to configure the complete picture.
Let's assume there is one client that has access to the different Api's, where each Api is a resource/scope.
The client needs to be allowed to access the Api's on behalf of the user, because the client can't access the resource without user.
So the client should be allowed to use certain scopes, where the scope needs to be requested by the client. Without this, a client can't access a resource. Suppose the client is configured for
Api1
andApi2
, but onlyApi1
is requested by the client. ThenApi2
andApi3
are not reachable.This is all part of the authorization at top level. Now it's time to involve the user. When the client accesses the api then the api knows which user made the request (as
sub
is part of the access token). But that is not enough to grant or deny access.So you'll need something to authorize the user. There are many options on how to implement this. Take a look at the documentation.
Consider a simple implementation where there are three policies. And each policy makes sure that only the matching type of user has access.
Then the actual question is, how to distinguish the type of user?
You can add a claim in the UserClaims table. Let's assume ClaimType is
UserType
and value is1
. In the resource add a policy that checks for the claimUserType
and the required value.In order to let IdentityServer add the claim to the access token, make sure the claimType is part of the scope (or ApiResource when multiple scopes are configured and need the claimType).
By adding the claimType
UserType
to theApi_
scope, means that when accessing the scope, the claim must be included. IdentityServer tries to limit the number of claims in the access token by filtering on requested claims only.When the user accesses the Api_, then the claim should be part of the access token (assuming the claim is set for each user, otherwise the user has no access at all). You can repeat this setup for the other api's (scopes).
In this case, I think this is an acceptable solution. Other options are authorization at a lower level (resource based) or outsourced, like PolicyServer.
Please note that because of SSO it may be possible that the user is authenticated by other clients as well. But since access is granted to certain types of users only (as part of the policies), you can prevent other types of users to access the resources that are not meant for them. You can prevent this behaviour by disabling automatic login.