I have an ASP .NET MVC project using Azure Active Directory for Authentication and I would like to store information in the claims (ClaimsIdentity) like a custom UserId.
I would then want to retrieve the custom UserId from the claims to check if user is authorized to access some page.
Where are these custom claims being stored? Would the user be able to modify the values in the claims?
It is common in most back end apps to need to use tokens from multiple places:
OAuth token claims
Product claims
In MVC there is usually an OnTokenValidated method you can override to customise the claims identity with product claims, as in this article.
The custom claims are then carried around in an HTTP only / encrypted authentication cookie.
Related
How can I add claims after token validation? (i.e. in a controller)
In my app users authenticate with Azure B2C, but I want roles (or claim authorization) to be based on what a user selects after they log in...
I know I can add claims inside OnTokenValidated, but I want to do this after the user goes to a page and makes a selection.
As far as I know, it's impossible. The asp.net core authentication will generate the claim based on the token. If you add the claims in the controller but not update the token, that means the claim will not add into the token.
Next time, when the user login in, the claim is as same as the previous one. The token will not be modified.
Since you are using Azure B2C, that means we couldn't modify the token on the server.
I'd like to ask for advice or direction to any article/documentation on how to add custom claims to user identity. Project I am working on is using Azure B2C with Microsoft.Identity.Web.
I am searching for a robust way of adding a custom claim during web request in an web app. The claim would contain permissions obtained from an application database. So I also need a way to store that claim between requests, so I don't trip to database on every request.
The model of roles and permissions stored in the database is quite complex and dynamic (managed by admins), thus simple storing custom claim in B2C via graph API is an option.
I was thinking about stepping in with a middleware doing claims transformation:
Is this ok with Microsoft.Identity.Web or is it something that I shouldn't do?
Still not sure how to persist the claim between requests - is there any robust way while using Microsoft.Identity.Web?
If you want to have permissions in the token, and I presume that would be the optimal way, then I'd go with saving those in the user object as a Base64 encoded JSON for example. You can have quite complex structure which AAD B2C would just return in the token for the user. Then you may do what you want with this value in once it hits your API. It's in the token so it's properly signed and you get the token with every request so you don't think about reaching to any database.
I have couple of applications. I will call them application-1 and application-2 in the question. My applications use asp.net core 2.2.
I register user using B2C custom policies like in this example
Azure B2C custom policies . I've added a REST API claim exchange to get user groups from the B2C. Just like this example. I retrieve the user groups in an azure function by calling memberOf in graph api.
When user completes the registration and enters first time in the system,they are redirected to application-1. They don't have any groups assigned to them in B2C. Then in the application-1 they have option to select which group they want to join. Once they select which group they want to join, I update the B2C.
If I use refresh token provided in the documentation located at Microsoft B2C reference OAuth and access id_token from the response I don't find groups in the claims. I decoded the token for which I have used SecurityTokenHandler class.
Also My application-1 has a link to application-2 which is also part of this B2C single sign on. When user clicks the link in application-1 they are redirected into application-2 . But the id_token doesn't find latest group information which user had assigned to themselves in the application-1.
Is there anyway to make sure the id_token carries latest group information in claims?
I'm still trying to understand B2C / Single sign . Please fill free to correct my terminologies if I've used wrong terms.
I am trying to implement an IdentityServer4 with Asp.Net Core Identity.
I want to use IdentityServer4 as centralized authentication/authorization point for APIs using always the same identity.
So the idea is to store the Asp.Net Core Identity stuff in an SQL Database which serves as the identity store.
The question now is how to map the centralized identity to application specific data.
I want to use same identity user in several applications, but in each application the user has other related entities, roles etc.
I read through the documentation of IdentityServer4 but could not find anything related to a proposed structure.
As I understood, you somehow map the identity id to your local application user.
Basic data like firstname etc are stored in the centralized identity store and application specific data is stored in the application specific database. So you would not save firstname etc in the application specific db right?
In the every request where you need user specific data will query the identity server to get information/claims?
What about registration process?
Does anybody have a clear structure setup which could be used to understand the whole setup?
(Separation like Asp.Net Identity Provider, IdentityServer4, Protected Api.)
So you would not save firstname etc in the application specific db
right?
Yes, User specific properties should go into the user profile and should be saved in the user store(database) of IdentityServer. Application specific user data should be stored in the application store.
In the every request where you need user specific data will query the
identity server to get information/claims?
Not necessarily, The user specific data can be included in identity token as claims. The claims will then be stored in a cookie as authentication ticket. For each request, those claims(stored in cookie/s) are available via User property of the controller
var identity = (ClaimsIdentity)User.Identity;
IEnumerable<Claim> claims = identity.Claims;
You can store and query application related user data stored against a user Id(sub claim can be used as a user Id).
If you need a lot of user-specific data in an application it is not optimal to include everything in identity-token and it is unlikely that you will need those for each request. So when you need extra information you can query UserInfo endpoint of identity server. Just include basic information you need to identify a user in your identity token.
What about the registration process?
Registration is a completely separate workflow that there is no involvement with identity server. You just need to save the user to identity store(probably using asp.net identity). Of course, you can host the registration controllers along with identity server, so that identity-related stuff is physically on the same server. You can also just write to IdentityServer user store from anyplace you host your registration process(e.g. A separate admin UI, or From a workflow involving email verification, manual approval etc...)
To customize what you store in Asp.net Core Identity, you need to use
services.AddIdentity<ApplicationUser, ApplicationRole>. ApplicationUser and ApplicationRole are extending IdentityUser and IdentityRole. This way you can make it store any extra info you want.
Then to return the extra info you need to create a ProfileService that implements IProfileService. With this service, you can add any extra information to claim tokens.
You need to register this service as
services.AddSingleton<IProfileService, ProfileService>();
builder.AddAspNetIdentity<ApplicationUser>().AddProfileService<ProfileService>();
You can register the user with extra info like below:
var user = new ApplicationUser
{
UserName = Username,
Email = email,
ExtraInfo1 = "Hello",
ExtraInfo2 = "World"
};
await _userManager.CreateAsync(user, "SomePassword");
With OpenId you have default set of claims associated with user. So any client application can access those claims. Make sure each client has openid and profile scopes assigned to them. Otherwise client application not able to access the users basic details.
In Asp.Net Core application you can access those claims in controller using User property.
I have users that're part of Roles which have Claims specified for them. I authenticate my users using IdentityServer (version 3 at the moment) with IncludeAllClaimsForUser set to true. I expected IdentityServer to automatically retrieve Role Claims but it doesn't.
Is there a way to make IdentityServer care about Role Claims or is customizing through ProfileServer is the only way to go?
if you need user information you have to use userinfo endpoint or while making a request for token add the scope that is related to user claim.