Search code examples
asp.net-coreidentityserver4

Provide token with identity server 4 only if the user fulfills certain conditions


I made a reasearch for about a week and i didn't find any solution to my question.

I'm using a ASP.NET Core Identity on .NET Core 2 Api and an identity server 4 to authenticate a user from the Angular 4 client app.

My question is: Is there any solution to provide a token from the /connect/token endpoint to a user only if he fulfills certain values from the database (e.g. EmailConfirmed is 1 (true) and so on).

If I wasn't clear enough please leave a comment below.


Solution

  • You can use IProfileService as an extension point.

    The IdentityServer4.AspNetIdentity package already provides an ProfileService<TUser> (see source) class which can be extended with the desired behavior.

    There you can override the IsActiveAsync method and add your desired logic.

    public class ConfirmedUsersProfileService : ProfileService<TUser>
    {
        public override async Task IsActiveAsync(IsActiveContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            context.IsActive = user != null && user.EmailConfirmed == true;
        }
    }
    

    When the user is either not existing in the database or his email is not confirmed, he won't be signed in and hence, no token be returned.

    This is also clearly described in the official Identity4 Docs.

    IsActiveAsync

    The API that is expected to indicate if a user is currently allowed to obtain tokens. It is passed an instance of IsActiveContext.

    Then register the new ConfirmedUsersProfileService instead of the old service:

    services.AddIdentityServer()
        ...
        .AddProfileService<ConfirmedUsersProfileService>();
    

    Also, can i made SQL Queries at the identity server level, somehow?

    Yes, you can inject any service into the ConfirmedUsersProfileService, i.e. the IdentityDbContext<TUser> or UserManager<TUser> (which is already injected, you just need to hold a reference to it in your derived class, as the fields in the ProfileService<TUser> are marked as private.) and then perform any query on it.

    P.S. The IProfileService can and should also be used as token extension points. You can add additional (or remove existing) claims from the token at this point too.