Roman Kolesnikov
Roman Kolesnikov

Reputation: 12147

Using email in token request with IdentityServer4

I'm usin ROPC flow with IdentityServer4 with ASP.NET Core Identity where I need to send username and password to /connect/token endpoint to get access_token.

How to configure IdentityServer4 to accept either Username or Email, and password in /connect/token requests?

PS: asp.net core: 2.0.2 IdentityServer4: 2.0.2

Upvotes: 4

Views: 1188

Answers (2)

Amir
Amir

Reputation: 2052

You need to override the ValidateAsync by creating the Custom PasswordValidator class which implement IResourceOwnerPasswordValidator interface like below.

  public class OwnerPasswordValidatorService : IResourceOwnerPasswordValidator
        {
            public UserManager<ApplicationUser> _userManager { get; }
            public OwnerPasswordValidatorService(UserManager<ApplicationUser> userManager)
            {
                _userManager = userManager;
            }
    
            public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
            {
                var user = await _userManager.FindByNameAsync(context.UserName);
    
                if (user == null)
                {
                    user = await _userManager.FindByEmailAsync(context.UserName);
    
                    if (user == null)
                    {
                      

  context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "Username or password is incorrect");
                    return;
                }
            }

            var passwordValid = await _userManager.CheckPasswordAsync(user, context.Password);
            if (!passwordValid)
            {
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "Username or password is incorrect");
                return;

            }

            context.Result = new GrantValidationResult(subject: context.UserName, authenticationMethod: "custom");
        }
    }     

Then configure your dependency for your custom class like below.

services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                 ...
                .AddAspNetIdentity<ApplicationUser>()
                .AddResourceOwnerValidator<OwnerPasswordValidatorService>() //here
                .AddProfileService<ProfileService>();

If any one still cannot make it work let me know. I will be happy to help.

Upvotes: 0

Roman Kolesnikov
Roman Kolesnikov

Reputation: 12147

Found this solution:

1) Copy file IdentityServer4.AspNetIdentity/src/IdentityServer4.AspNetIdentity/ResourceOwnerPasswordValidator.cs to your project from https://github.com/IdentityServer/IdentityServer4.AspNetIdentity/blob/dev/src/IdentityServer4.AspNetIdentity/ResourceOwnerPasswordValidator.cs

2) Fix ValidateAsync method to find user with email

        var user = await _userManager.FindByNameAsync(context.UserName);
        if (user == null) {
            user = await _userManager.FindByEmailAsync(context.UserName);
        }

3) Add Validator to IS4:

            .AddAspNetIdentity<AppUser>()
            .AddResourceOwnerValidator<Services.ResourceOwnerPasswordValidator<AppUser>>();

4) Profit!

Upvotes: 5

Related Questions