Bit of Technology

  • Archive
  • About Me
    • Advertise
    • Disclaimer
  • Speaking
  • Contact

ASP.NET Identity 2.1 Accounts Confirmation, and Password Policy Configuration – Part 2

February 3, 2015 By Taiseer Joudeh 111 Comments

Be Sociable, Share!

  • Tweet
  • Email
  • WhatsApp

This is the second part of Building Simple Membership system using ASP.NET Identity 2.1, ASP.NET Web API 2.2 and AngularJS. The topics we’ll cover are:

  • Configure ASP.NET Identity with ASP.NET Web API (Accounts Management) – Part 1.
  • ASP.NET Identity 2.1 Accounts Confirmation, and Password/User Policy Configuration – (This Post)
  • Implement OAuth JSON Web Tokens Authentication in ASP.NET Web API and Identity 2.1 – Part 3
  • ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4
  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
  • AngularJS Authentication and Authorization with ASP.NET Web API and Identity 2.1 – Part 6

The source code for this tutorial is available on GitHub.

ASP.NET Identity 2.1 Accounts Confirmation, and Password/User Policy Configuration

In this post we’ll complete on top of what we’ve already built, and we’ll cover the below topics:

  • Send Confirmation Emails after Account Creation.
  • Configure User (Username, Email) and Password policy.
  • Enable Changing Password and Deleting Account.

1 . Send Confirmation Emails after Account Creation

FeaturedImage

ASP.NET Identity 2.1 users table (AspNetUsers) comes by default with a Boolean column named “EmailConfirmed”, this column is used to flag if the email provided by the registered user is valid and belongs to this user in other words that user can access the email provided and he is not impersonating another identity. So our membership system should not allow users without valid email address to log into the system.

The scenario we want to implement that user will register in the system, then a confirmation email will be sent to the email provided upon the registration, this email will include an activation link and a token (code) which is tied to this user only and valid for certain period.

Once the user opens this email and clicks on the activation link, and if the token (code) is valid the field “EmailConfirmed” will be set to “true” and this proves that the email belongs to the registered user.

To do so we need to add a service which is responsible to send emails to users, in my case I’ll use Send Grid which is service provider for sending emails, but you can use any other service provider or your exchange change server to do this. If you want to follow along with this tutorial you can create a free account with Send Grid which provides you with 400 email per day, pretty good!

1.1 Install Send Grid

Now open Package Manager Console and type the below to install Send Grid package, this is not required step if you want to use another email service provider. This packages contains Send Grid APIs which makes sending emails very easy:

MS DOS
1
install-package Sendgrid

1.2 Add Email Service

Now add new folder named “Services” then add new class named “EmailService” and paste the code below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    public class EmailService : IIdentityMessageService
    {
        public async Task SendAsync(IdentityMessage message)
        {
            await configSendGridasync(message);
        }
 
        // Use NuGet to install SendGrid (Basic C# client lib)
        private async Task configSendGridasync(IdentityMessage message)
        {
            var myMessage = new SendGridMessage();
 
            myMessage.AddTo(message.Destination);
            myMessage.From = new System.Net.Mail.MailAddress("taiseer@bitoftech.net", "Taiseer Joudeh");
            myMessage.Subject = message.Subject;
            myMessage.Text = message.Body;
            myMessage.Html = message.Body;
 
            var credentials = new NetworkCredential(ConfigurationManager.AppSettings["emailService:Account"],
                                                    ConfigurationManager.AppSettings["emailService:Password"]);
 
            // Create a Web transport for sending email.
            var transportWeb = new Web(credentials);
 
            // Send the email.
            if (transportWeb != null)
            {
                await transportWeb.DeliverAsync(myMessage);
            }
            else
            {
                //Trace.TraceError("Failed to create Web transport.");
                await Task.FromResult(0);
            }
        }
    }

What worth noting here that the class “EmailService” implements the interface “IIdentityMessageService”, this interface can be used to configure your service to send emails or SMS messages, all you need to do is to implement your email or SMS Service in method “SendAsync” and your are good to go.

In our case we want to send emails, so I’ve implemented the sending process using Send Grid in method “configSendGridasync”, all you need to do is to replace the sender name and address by yours, as well do not forget to add 2 new keys named “emailService:Account” and “emailService:Password” as AppSettings to store Send Grid credentials.

After we configured the “EmailService”, we need to hock it with our Identity system, and this is very simple step, open file “ApplicationUserManager” and inside method “Create” paste the code below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
//Rest of code is removed for clarity
appUserManager.EmailService = new AspNetIdentity.WebApi.Services.EmailService();
 
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
appUserManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
{
//Code for email confirmation and reset password life time
TokenLifespan = TimeSpan.FromHours(6)
};
}
  
return appUserManager;
}

As you see from the code above, the “appUserManager” instance contains property named “EmailService” which you set it the class we’ve just created “EmailService”.

Note: There is another property named “SmsService” if you would like to use it for sending SMS messages instead of emails.

Notice how we are setting the expiration time for the code (token) send by the email to 6 hours, so if the user tried to open the confirmation email after 6 hours from receiving it, the code will be invalid.

1.3 Send the Email after Account Creation

Now the email service is ready and we can start sending emails after successful account creation, to do so we need to modify the existing code in the method “CreateUser” in controller “AccountsController“, so open file “AccountsController” and paste the code below at the end of the method:

C#
1
2
3
4
5
6
7
8
9
10
11
//Rest of code is removed for brevity
 
string code = await this.AppUserManager.GenerateEmailConfirmationTokenAsync(user.Id);
 
var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code = code }));
 
await this.AppUserManager.SendEmailAsync(user.Id,"Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
 
Uri locationHeader = new Uri(Url.Link("GetUserById", new { id = user.Id }));
 
return Created(locationHeader, TheModelFactory.Create(user));

The implementation is straight forward, what we’ve done here is creating a unique code (token) which is valid for the next 6 hours and tied to this user Id only this happen when calling “GenerateEmailConfirmationTokenAsync” method, then we want to build an activation link to send it in the email body, this link will contain the user Id and the code created.

Eventually this link will be sent to the registered user to the email he used in registration, and the user needs to click on it to activate the account, the route “ConfirmEmailRoute” which maps to this activation link is not implemented yet, we’ll implement it the next step.

Lastly we need to send the email including the link we’ve built by calling the method “SendEmailAsync” where the constructor accepts the user Id, email subject, and email body.

1.4 Add the Confirm Email URL

The activation link which the user will receive will look as the below:

XHTML
1
http://localhost/api/account/ConfirmEmail?userid=xxxx&code=xxxx

So we need to build a route in our API which receives this request when the user clicks on the activation link and issue HTTP GET request, to do so we need to implement the below method, so in class “AccountsController” as the new method as the below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
        [HttpGet]
        [Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
        public async Task<IHttpActionResult> ConfirmEmail(string userId = "", string code = "")
        {
            if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(code))
            {
                ModelState.AddModelError("", "User Id and Code are required");
                return BadRequest(ModelState);
            }
 
            IdentityResult result = await this.AppUserManager.ConfirmEmailAsync(userId, code);
 
            if (result.Succeeded)
            {
                return Ok();
            }
            else
            {
                return GetErrorResult(result);
            }
        }

The implementation is simple, we only validate that the user Id and code is not not empty, then we depend on the method “ConfirmEmailAsync” to do the validation for the user Id and the code, so if the user Id is not tied to this code then it will fail, if the code is expired then it will fail too, if all is good this method will update the database field “EmailConfirmed” in table “AspNetUsers” and set it to “True”, and you are done, you have implemented email account activation!

Important Note: It is recommenced to validate the password before confirming the email account, in some cases the user might miss type the email during the registration, so you do not want end sending the confirmation email for someone else and he receives this email and activate the account on your behalf, so better way is to ask for the account password before activating it, if you want to do this you need to change the “ConfirmEmail” method to POST and send the Password along with user Id and code in the request body, you have the idea so you can implement it by yourself 🙂

2. Configure User (Username, Email) and Password policy

2.1 Change User Policy

In some cases you want to enforce certain rules on the username and password when users register into your system, so ASP.NET Identity 2.1 system offers this feature, for example if we want to enforce that our username only allows alphanumeric characters and the email associated with this user is unique then all we need to do is to set those properties in class “ApplicationUserManager”, to do so open file “ApplicationUserManager” and paste the code below inside method “Create”:

C#
1
2
3
4
5
6
7
//Rest of code is removed for brevity
//Configure validation logic for usernames
appUserManager.UserValidator = new UserValidator<ApplicationUser>(appUserManager)
{
AllowOnlyAlphanumericUserNames = true,
RequireUniqueEmail = true
};

2.2 Change Password Policy

The same applies for the password policy, for example you can enforce that the password policy must match (minimum 6 characters, requires special character, requires at least one lower case and at least one upper case character), so to implement this policy all we need to do is to set those properties in the same class “ApplicationUserManager” inside method “Create” as the code below:

C#
1
2
3
4
5
6
7
8
9
10
//Rest of code is removed for brevity
//Configure validation logic for passwords
appUserManager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = false,
RequireLowercase = true,
RequireUppercase = true,
};

2.3 Implement Custom Policy for User Email and Password

In some scenarios you want to apply your own custom policy for validating email, or password. This can be done easily by creating your own validation classes and hock it to “UserValidator” and “PasswordValidator” properties in class “ApplicationUserManager”.

For example if we want to enforce using only the following domains (“outlook.com”, “hotmail.com”, “gmail.com”, “yahoo.com”) when the user self registers then we need to create a class and derive it from “UserValidator<ApplicationUser>” class, to do so add new folder named “Validators” then add new class named “MyCustomUserValidator” and paste the code below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    public class MyCustomUserValidator : UserValidator<ApplicationUser>
    {
 
        List<string> _allowedEmailDomains = new List<string> { "outlook.com", "hotmail.com", "gmail.com", "yahoo.com" };
 
        public MyCustomUserValidator(ApplicationUserManager appUserManager)
            : base(appUserManager)
        {
        }
 
        public override async Task<IdentityResult> ValidateAsync(ApplicationUser user)
        {
            IdentityResult result = await base.ValidateAsync(user);
 
            var emailDomain = user.Email.Split('@')[1];
 
            if (!_allowedEmailDomains.Contains(emailDomain.ToLower()))
            {
                var errors = result.Errors.ToList();
 
                errors.Add(String.Format("Email domain '{0}' is not allowed", emailDomain));
 
                result = new IdentityResult(errors);
            }
 
            return result;
        }
    }

What we have implemented above that the default validation will take place then this custom validation in method “ValidateAsync” will be applied, if there is validation errors it will be added to the existing “Errors” list and returned in the response.

In order to fire this custom validation, we need to open class “ApplicationUserManager” again and hock this custom class to the property “UserValidator” as the code below:

C#
1
2
3
4
5
6
7
//Rest of code is removed for brevity
//Configure validation logic for usernames
appUserManager.UserValidator = new MyCustomUserValidator(appUserManager)
{
AllowOnlyAlphanumericUserNames = true,
RequireUniqueEmail = true
};

Note: The tutorial code is not using the custom “MyCustomUserValidator” class, it exists in the source code for your reference.

Now the same applies for adding custom password policy, all you need to do is to create class named “MyCustomPasswordValidator” and derive it from class “PasswordValidator”, then you override the method “ValidateAsync” implementation as below, so add new file named “MyCustomPasswordValidator” in folder “Validators” and use the code below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public class MyCustomPasswordValidator : PasswordValidator
    {
        public override async Task<IdentityResult> ValidateAsync(string password)
        {
            IdentityResult result = await base.ValidateAsync(password);
 
            if (password.Contains("abcdef") || password.Contains("123456"))
            {
                var errors = result.Errors.ToList();
                errors.Add("Password can not contain sequence of chars");
                result = new IdentityResult(errors);
            }
            return result;
        }
    }

In this implementation we added some basic rule which checks if the password contains sequence of characters and reject this type of password by adding this validation result to the Errors list, it is exactly the same as the custom users policy.

Now to attach this class as the default password validator, all you need to do is to open class “ApplicationUserManager” and use the code below:

C#
1
2
3
4
5
6
7
8
9
10
//Rest of code is removed for brevity
// Configure validation logic for passwords
appUserManager.PasswordValidator = new MyCustomPasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = false,
RequireLowercase = true,
RequireUppercase = true,
};

All other validation rules will take place (i.e checking minimum password length, checking for special characters) then it will apply the implementation in our “MyCustomPasswordValidator”.

3. Enable Changing Password and Deleting Account

Now we need to add other endpoints which allow the user to change the password, and allow a user in “Admin” role to delete other users account, but those end points should be accessed only if the user is authenticated, we need to know the identity of the user doing this action and in which role(s) the user belongs to. Until now all our endpoints are called anonymously, so lets add those endpoints and we’ll cover the authentication and authorization part next.

3.1 Add Change Password Endpoint

This is easy to implement, all you need to do is to open controller “AccountsController” and paste the code below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        [Route("ChangePassword")]
        public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
 
            IdentityResult result = await this.AppUserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
 
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }
 
            return Ok();
        }

Notice how we are calling the method “ChangePasswordAsync” and passing the authenticated User Id, old password and new password. If you tried to call this endpoint, the extension method “GetUserId” will not work because you are calling it as anonymous user and the system doesn’t know your identity, so hold on the testing until we implement authentication part.

The method “ChangePasswordAsync” will take care of validating your current password, as well validating your new password policy, and then updating your old password with new one.

Do not forget to add the “ChangePasswordBindingModel” to the class “AccountBindingModels” as the code below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    public class ChangePasswordBindingModel
    {
        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Current password")]
        public string OldPassword { get; set; }
 
        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "New password")]
        public string NewPassword { get; set; }
 
        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Confirm new password")]
        [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    
    }

3.2 Delete User Account

We want to add the feature which allows a user in “Admin” role to delete user account, until now we didn’t introduce Roles management or authorization, so we’ll add this end point now and later we’ll do slight modification on it, for now any anonymous user can invoke it and delete any user by passing the user Id.

To implement this we need add new method named “DeleteUser” to the “AccountsController” as the code below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        [Route("user/{id:guid}")]
        public async Task<IHttpActionResult> DeleteUser(string id)
        {
 
            //Only SuperAdmin or Admin can delete users (Later when implement roles)
 
            var appUser = await this.AppUserManager.FindByIdAsync(id);
 
            if (appUser != null)
            {
                IdentityResult result = await this.AppUserManager.DeleteAsync(appUser);
 
                if (!result.Succeeded)
                {
                    return GetErrorResult(result);
                }
 
                return Ok();
 
            }
 
            return NotFound();
          
        }

This method will check the existence of the user id and based on this it will delete the user. To test this method we need to issue HTTP DELETE request to the end point “api/accounts/user/{id}”.

The source code for this tutorial is available on GitHub.

In the next post we’ll see how we’ll implement Json Web Token (JWTs) Authentication and manage access for all the methods we added until now.

Follow me on Twitter @tjoudeh

References

  • Featured Image Source

Be Sociable, Share!

  • Tweet
  • Email
  • WhatsApp

Related Posts

  • Integrate Azure AD B2C with ASP.NET MVC Web App – Part 3
  • Secure ASP.NET Web API 2 using Azure AD B2C – Part 2
  • Azure Active Directory B2C Overview and Policies Management – Part 1
  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
  • ASP.NET Identity 2.1 with ASP.NET Web API 2.2 (Accounts Management) – Part 1

Filed Under: ASP.NET, ASP.NET Identity, ASP.Net Web API, Web API Tutorial Tagged With: Token Authentication, Tutorial, Web API 2

Comments

  1. Liam says

    February 3, 2015 at 2:45 am

    Good article, but you should really change all the references to ‘He/him’ etc to something gender neutral.

    Reply
    • Taiseer Joudeh says

      February 3, 2015 at 4:08 am

      Thanks Liam for your comment, It was a mistake, all is fixed now, thanks again 🙂

      Reply
  2. Akinsanya Olanrewaju says

    February 9, 2015 at 12:14 pm

    Your Post have been a life saving material for us in my region, with all your past post and this, you have change our thinking toward DotNet Development. Thanks.

    Please we need this series to be completed on time, so as to use it to complete our school project.
    (We are student from Africa), We enjoy your series.

    Thanks.

    Reply
    • Taiseer Joudeh says

      February 13, 2015 at 8:06 pm

      Glad to hear this, happy to know that I’m helping students in other contents to learn some cool technologies, good luck 🙂

      Reply
  3. AndreasF says

    February 10, 2015 at 1:16 pm

    When is the next post? Waiting for it!
    Nice posts. Identity is hard for me to understand because it has so many functions.
    It’s the first time i begin understanding it. Thanks!

    Reply
    • Taiseer Joudeh says

      February 10, 2015 at 3:56 pm

      Glad it was useful, most probably tomorrow 🙂 keep tuned!

      Reply
  4. Kurai says

    February 11, 2015 at 3:29 pm

    Been here in the past months and I am learning new things in every post you have.. –I’m just another kid who wants to be something great.. and I tell you.. when that happen.. I will put your name as one my “hero”… Thank you so much…

    Reply
    • Taiseer Joudeh says

      February 11, 2015 at 3:40 pm

      Thanks for your sweet message, I’m really happy to know that my contribution is helping a lot of people out there, love what you do and have passion for it and I’m sure you will be a shining star =)

      Reply
  5. Tony Pollard says

    February 12, 2015 at 6:32 pm

    I’ve been following you for some time now, and I appreciate your approach to start with an empty project and add what you need with adequate explanation as you go. I find myself eager and watching for your next post as you are regular reading for me. Great job Taiseer!

    Reply
    • Taiseer Joudeh says

      February 13, 2015 at 8:00 pm

      Thank you Tony for your comment, glad to know that posts are useful. Part 3 is ready and should be published this Monday.

      Reply
  6. Miguel Delgado says

    February 16, 2015 at 8:04 am

    Hello Taisser, thanks for all your posts and very happy to see you MVP.

    Alas, I hit a bit of a bump implementing your code. I create the user and while creating the link to send the confirmation email, it raises an exception:

    on the instruction
    var callbackUrl = new Uri(Url.Link(“ConfirmEmailRoute”, new { userId = user.Id, code = code }));

    the Url.Link raises the exception
    {“Value cannot be null.\r\nParameter name: request”}

    I checked the function signature and it matches…

    Do you have any idea on how to fix this… I can always hardcode the uri, but I’d rather suffer the pains of hell…

    Thanks in advance

    Miguel Delgado

    Reply
    • Taiseer Joudeh says

      February 16, 2015 at 10:23 am

      Hi Miguel,
      Thanks for your nice words,
      Double check that you have created and named the route “ConfirmEmailRoute” correctly, as well you are passing the exact parameters. This is only what I can think of now.
      Download the repo and compare the code, I’m sure there is simple glitch there.
      Hope this helps!

      Reply
  7. Diego says

    February 19, 2015 at 3:33 am

    Hi Taiseer,
    What´s the point in creating an email confirmation api endpoint?
    The user will see nothing else than a white screen in the browser.
    The logical thing would be creating a web page to show a confirmation message, but I guess in this post you just wanted to focus on webapi.

    Apart from that, please tell me what you think about this

    In my case, I´m implementing all this from a mobile application and I´m trying to make things easy to the user. Imagine the situation: a user registers in the app and receives a message asking him/her to check the email. The email will redirect the user to a web page (confirmation page), and then, that user has to go back to the app. 4 step process (including registration form) is a bit overhead IMO.

    So I was thinking about sending a short code (like the kind of sms confirmation codes) to the email so the user can just write it in a textbox (inside the mobile app) instead of using urls. I´m not sure if there is any way to modify the confirmation token asp.net generates to make for example, a 4 character number code. In that case you could see the code in the push notification of your email box and even no need to open it

    Any thoughts?

    Reply
    • Taiseer Joudeh says

      February 19, 2015 at 8:47 pm

      Hi Diego,
      As you suggested you need to build a GUI on your system where in contains a link for the “ConfirmEmailRoute” end point, once the user invokes this endpoint (click on that link) and you receive 200 OK status from the API, youir GUI needs to display confirmation message and maybe redirect him to the application as this SO question. Never tried it before 🙂
      Regarding send SMS, as you suggested here you are going to send the SMS to the email so the user might need to open the email to read the SMS code there and then close the email and go back to application to enter it, so the same number of steps.
      As well I’m not sure if you can generate friendly token (4 digits) and attach it to the user Id so the validation for this token happens seamlessly as it happens in method “AppUserManager.ConfirmEmailAsync”, I need to check this.

      Reply
      • Diego says

        February 19, 2015 at 9:46 pm

        Hi Taiseer,

        About the fiendly token:
        If you do something like this in your asp.net userManager…

        > IDataProtector dataProtector = dataProtectionProvider.Create(“ASP.NET Identity”);
        > this.UserTokenProvider = new DataProtectorTokenProvider(dataProtector);

        you get a huge token (kind of oAuth token), but I realized you can get a 6 digit “token” if you do this instead:

        > this.UserTokenProvider = new EmailTokenProvider();

        Not sure about the impact in the application or any related security issues… but I can say the confirmation works fine as well in this way.

        About the confirmation message:
        I´m not using legacy MVC in my project. Just webapi so I´m writing an html response like this:

        [ActionName(“emailconfirmation”)]
        public async Task ConfirmEmailAccount(string userId, string token)
        {
        IdentityResult result = await aspNetUserManager.ConfirmEmailAsync(userId, token);

        if (result.Succeeded)
        {
        string body = “bla bla bla””; // this will be a proper web page

        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StringContent(body, Encoding.UTF8, “text/html”);

        return response;
        }
        else
        {
        GetErrorResult(result.Errors);
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        }
        }

        About steps overhead and usability in mobile applications:

        I´ve been reading about this in stack-overflow and many people agree that email confirmations on mobile applications are a no-go for many users. Of course that depends on your project needs but reasonable in many cases. So a nice way to go would be:

        1. You send the welcome-confirmation email
        2. The user can start using the app without confirming
        3. After a time period you remind the user to confirm the account (by email)
        4. After another time period, if the account has not been confirmed, you just delete it (this can be done in a background scheduled job)

        That way, the users just trying to test your app will be able to do it quickly. And if they are interested after all, clicking a link shouldn´t be a problem.

        Thanks for your answer!

        ps: is there anyway to tag text as code in the comments?

        Reply
        • Diego says

          February 19, 2015 at 9:56 pm

          I forgot to mention about redirecting user to the app from the email box.
          That´s a nice solution if the user opens the email in the mobile device where the app is.
          This can be done (I´m using Xamarin) like this: http://developer.xamarin.com/recipes/cross-platform/app-links/app-links-ios/ and this: http://developer.xamarin.com/recipes/cross-platform/app-links/app-links-android/

          Reply
  8. Akinsanya Olanrewaju says

    March 13, 2015 at 1:56 pm

    I ran the source code from the updated one from github, after update the package manager, I want to the create a new account from the create end-point

    http://prntscr.com/6g70sh

    This is the error i get http://prntscr.com/6g70z4

    I have done all i needed to do, i dont know am doing wrong

    1. http://prntscr.com/6g7180
    2. http://prntscr.com/6g71s5 : Here, this is the credentials from my signup in sendgrid

    Can someone help me out.

    Reply
    • Taiseer Joudeh says

      March 16, 2015 at 5:15 pm

      This issue with the SendGrid service trying to send confirmation email, make sure you are using the same NuGet package I have used in the project by checking packages.config file and double check that SendGrid username and password are set correctly in web.config as you obtained them from SendGrid after creating a SendGrid account.

      Reply
  9. Regan says

    March 14, 2015 at 7:47 pm

    I dont get the interface >> IIdentityMessageService

    Reply
    • Taiseer Joudeh says

      March 16, 2015 at 5:20 pm

      What is not clear about it? It interface used to separate the implementation of your SMS service or Email service from Web API logic, it has method named “SendAsync” in order to implement your sending logic in it

      Reply
  10. Simon says

    March 25, 2015 at 11:02 pm

    Hi Taiseer,

    First off I would like to thank you for your post and all the information concerning JWT. I am currently doing an internship in a company where I was asked to do a small authentication and authorization using Identity + JWT. I ran into a small bug and I don’t know if its me that did not implement your explications properly but for some reason I cannot seem to be able to do any calls to Identity, for example User.Identity.GetUserId(); is always null. It feels like the data/information from my token does not get passed. Would you be able to give me any pointers or would you have any idea? I have been looking at your AngularJSAuthentication solution and all your other post and I can’t seem to be able to find out what it is.

    Thank you,

    Simon.

    Reply
    • Taiseer Joudeh says

      March 27, 2015 at 3:51 pm

      Hi Simon, are you calling the method User.Identity.GetUserId(); inside a protected controller? A controller or action method attributed with [Authorize]? If yes then the Identity should be set, can you try checking the property User.Identity.Name too? Does it return the authenticated UserId?

      Reply
      • felipefurlan says

        August 12, 2015 at 6:59 pm

        Hello Taisser, how are you doing? I’m having this issue too. The User.Identity.Name is OK, but the ID is always null. When I inspect the User.Identity on Imediate Window I receive the following:

        {System.Security.Claims.ClaimsIdentity}
        [System.Security.Claims.ClaimsIdentity]: {System.Security.Claims.ClaimsIdentity}
        AuthenticationType: “Bearer”
        IsAuthenticated: true
        Name: “bla@bla.com.br”

        I’m not sure if I’m missing something here.

        Reply
      • David says

        July 21, 2016 at 8:57 pm

        Hello Taiseer,

        I am also having the problem with User.Identity except User.Identity.Name = “”. Also for me IsAuthenticated = false. I can decode the JWT token and my username is contained therein. Not sure why Identity is not picking it up.

        Reply
    • Torsten Tiedt says

      November 10, 2016 at 1:52 pm

      Hi,

      I had the same issue. My user was authorized, but the returned UserId was null. I guess, the name claim has the wrong scheme. It had “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name” instead of “nameidentity” at the end. Thus the method returnes null.

      I solved it by using the name to get the id:

      userManager.FindByNameAsync(User.Identity.Name)

      Regards,

      Torsten

      Reply
      • Torsten Tiedt says

        November 10, 2016 at 3:54 pm

        I think I just found the origin of my problem why GetUserId() returns null. In the method “GrantResourceOwnerCredentials” of my AuthorizationServerProvider the claims are added to the user like this:

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
        identity.AddClaim(new Claim(“sub”, context.UserName));
        identity.AddClaim(new Claim(“role”, “user”));

        I guess if you add the claimtype “NameIdentifier” the GetUserId() method should return the user.

        Note: in my answer above I wrote “namedidentity”. I guess this is wrong and should be “NameIdentifier”.

        Regards,

        Torsten

        Reply
        • Taiseer Joudeh says

          November 12, 2016 at 12:14 am

          You are correct, the claim of type “NameIdentifier” should be used to return the UserId when calling GetUserId()

          Reply
  11. Akinsanya Olanrewaju says

    April 1, 2015 at 2:16 pm

    Hi,

    List _allowedEmailDomains = new List { “outlook.com”, “hotmail.com”, “gmail.com”, “yahoo.com” };

    How do i create a CustomUserValidator for user and admin email separately

    My application will be split into two admin registration and user registration

    I want the users to register with any email address (e.g gmail.com, yahoo.com) while the admin will only register with the official company email (e.g admin@company.com)

    How can i seperate the logic for this or conditionally configure this, since the validation logic for the user admin are called from one single point in the startup.cs

    Is it advisable to create the API for admin seperate from the user, or i can use thesame API for both logic.

    Thanks

    Reply
  12. Ernst Bolt says

    April 8, 2015 at 10:06 am

    Hi Taiseer,

    Microsoft.Owin.Testing doesn’t provide a DataProtectionProvider in the options parameter of ApplicationUserManager.Create(). I’ve changed the method to:

    …

    var dataProtectionProvider = options.DataProtectionProvider;
    if (dataProtectionProvider != null)
    {
    appUserManager.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create(“ASP.NET Identity”))
    {
    //Code for email confirmation and reset password life time
    TokenLifespan = TimeSpan.FromHours(6)
    };
    }
    else
    {
    var provider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider(“ASP.NET Identity”);
    UserManager userManager = new UserManager(new UserStore());
    appUserManager.UserTokenProvider = new DataProtectorTokenProvider(provider.Create(“ASP.NET Identity”)) {

    //Code for email confirmation and reset password life time
    TokenLifespan = TimeSpan.FromHours(6)

    };
    }

    …

    Now it’s working.

    Reply
  13. GRAPHC_coder says

    May 15, 2015 at 9:09 am

    Hi Taiseer,
    Great post! It really helps me on my project.
    Just a quick heads up for those who might experience same as mine.
    I was setting up our own SMTP server and testing email confirmation through Postman, “Invalid Token” happened for URL confirmation.
    Solution:
    http://tech.trailmax.info/2015/05/asp-net-identity-invalid-token-for-password-reset-or-email-confirmation/

    It works for me:
    CreateUser() add
    code = System.Web.HttpUtility.UrlEncode(code);
    ConfirmEmail() add
    code = System.Web.HttpUtility.UrlDecode(code);

    Reply
    • Taiseer Joudeh says

      May 15, 2015 at 11:48 pm

      Thanks for sharing this, what you are doing is better practice because the token might contain unsafe URL chars which needs to be Url encoded before.

      Reply
  14. Doug says

    June 27, 2015 at 3:11 am

    The callback URL is for a GET to the API, but how do you handle the case where the front end is solely Angular? How can I get the ConfirmEmail API function to, upon execution from the email link click event, redirect back to my front end Angular site after updating the EmailConfirmed flag?

    Reply
    • engineerumairshahen says

      February 21, 2016 at 7:24 pm

      @Doug were you able to find the solution if yes then please share with me

      Reply
      • Actias says

        June 6, 2016 at 9:30 am

        You can edit the call back URL at this section of code in the AccountsController

        var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
        var callbackUrl = new Uri(Url.Link(“ConfirmEmailRoute”, new { userId = user.Id, code }));

        await UserManager.SendEmailAsync(user.Id, “Confirm your account”, “Please confirm your account by clicking here“);

        Reply
  15. dush_a says

    July 9, 2015 at 3:21 am

    Hi Taiseer,
    I tried to create a free SendGrid account. They didn’t provide me an account since I do not have a website. Can you please show me how to use gmail or hotmail account instead SendGrid ? (even asp.net tutorials use sendGrid, it looks like they may have stoped the service for leaners, if you can provide a free email alternative it would be beneficial to new learners)

    This is what SendGrid support said:

    “Thank you for providing further information. Although to provision your account we’ll need to know what type of emails you’ll be sending using our service, the website provided during registration was not sufficient to help us determine this. Without a valid, working website upon which we can determine this, your account will not be provisioned. Please get back in touch with us when your website is nearing a state of completion.
    Best,
    IULIANA O.
    Technical Support Engineer
    SendGrid”

    Reply
  16. Mcshaz says

    July 10, 2015 at 1:33 am

    Thanks for posting this.

    just an expansion on the comment:
    “Notice how we are setting the expiration time for the code (token) send by the email to 6 hours”

    so far, my testing on the Indentity 2.1 framework would indicate that the token contains datetime information on when it was sent, rather than any data on when it is to expire. The ConfirmEmailAsync method then seems to apply the TokenLifespan as part of validating the token. The relevance of this is that changing TokenLifespan (in testing or production) will be effective retrospectively on tokens previously sent.

    Reply
  17. Nathan says

    August 4, 2015 at 9:45 pm

    Did you find that GenerateEmailConfirmationTokenAsync is creating a 500 character token? i.e. http://localhost/api/account/ConfirmEmail?userid=xxxx&code=
    Sending such a long URL is running up against spam filters in our case.

    Reply
    • Taiseer Joudeh says

      August 8, 2015 at 7:11 am

      Hi Nathan,
      To be honest I didn’t notice that huge number of generated characters, were you able to find solution for this issue?

      Reply
  18. Ali Morlo says

    August 13, 2015 at 4:21 pm

    Slm from Africa,

    thx for the stuff

    i’m unable to pull the namespace for AspNetIdentity.WebApi.Services.EmailService()

    Reply
    • Ali Morlo says

      August 13, 2015 at 4:35 pm

      I Got it Sorry, Just Need Some rest

      Reply
      • Taiseer Joudeh says

        August 15, 2015 at 1:09 am

        No problem Ali 🙂

        Reply
  19. Michael Heribert says

    September 10, 2015 at 5:35 pm

    Thank you for the good article! Although i followed your steps exactly, there seems to be an issue, at least for me: When i send a create-user request, the programme creates a new user, but does not call the EmailService class so no email is sent. Is this a known issue? Thanks in advance 🙂

    Reply
    • Taiseer Joudeh says

      September 10, 2015 at 6:37 pm

      Hi Michael, glad you liked it, I guess you are missing registering the service in AppUserManager as this LOC. If it is already there, check that your SendGrid ApiId and Secret are correct.
      Hope this will help.

      Reply
      • Michael Heribert says

        September 10, 2015 at 7:50 pm

        Hi, thank you for your quick response! I checked the registering of the EmailService in AppUserManager, that wasn’t the problem. The credentials for the SendGridAPI are fine aswell. But by inserting Debug.writeline commands i found out that the ApplicationUserManager class is not called. I tried your downloaded your version from github and there it worked just perfectly and the output-commands were shown in the console. Do you know anything else that could be the problem?

        Reply
  20. mazin says

    September 18, 2015 at 8:51 am

    Hi Taiseer, Great article, all your articles have helped me a lot, thanks so much.
    I’m still a bit confused about the emailservice, I followed your AngularJsAuthentication tutorials and so i dont have a ApplicationUserManager class or a “Create” method to plug in the the EmailService with Identity system, where should I place the body of code?

    Reply
    • Taiseer Joudeh says

      September 18, 2015 at 2:34 pm

      Hi Mazin,
      If you need to use the email service to send emails, then you have to user the ASP.NET Identity system and create an instance of the UserManager, and assign the “EmailService” property to your email sending logic, hope this somehow clarifies your concern.

      Reply
  21. johnatangarcia says

    October 4, 2015 at 9:37 am

    Yeah, I totally should buy you a beer. Thanks for the very detailed information!

    Reply
    • Taiseer Joudeh says

      October 12, 2015 at 10:58 am

      You are welcome, happy to help 🙂

      Reply
  22. Steven Duque says

    October 11, 2015 at 4:40 am

    Hello Taiseer,
    I have a quick question. May be simple however I’ve googled away and haven’t exactly found the answer I am looking for. SO I am building a web app that utilizes AngularJS for the Frontend. Specifically using the Ui,router rather than ngRoute. So I configured a state(route) that has the parameters of UserId and Code in order to use the parameters in my ConfirmEmailController.js . In the ConfirmEmailController.js I call to the Account controller which will then confirm the email. Upon failure or success the html will display the response message. My Issue is this… In the email that gets sent to the User, the link needs to be something like this Here
    However, in the AccountController.cs under method Register() , I cannot get the callbackUrl to be correct. I mean it does output the link as I would expect, but when clicked I get this error “The request filtering module is configured to deny a request that contains a double escape sequence.” . So I ask you how can I build a link that will pass the UserId and Code in an email that doesn’t compromise the built in security that’s blocking double spacing, but handle the View and Controller in Angular. OR Am I putting much more work into it than I need to and there is a simpler way to accomplish this? Thank you for taking the time to read and respond to my question! Sorry for the long message but I wanted to be thorough.

    Reply
    • Taiseer Joudeh says

      October 12, 2015 at 10:04 am

      Hi Steven,

      I’m not sure if you need to URL encode the code generated then decode it once you receive it, this is the only thing that I’m suspecting now. As well you might try sending the activation code as a query string not part of the URI.

      Let me know if this solve your issue.

      Reply
      • Steven Duque says

        October 15, 2015 at 7:08 am

        Hello! And thank you for your reply! I ended up sending it as query strings. Both userId and code. Just have to have the user login and it’ll call to the api/Account . My only issue is that the ‘+’ in the userId’s gets replaced by spaces. Its Angular. It used to be encoded as %2B which is what I need, however many people filed issues with it on github because they needed it to be treated as %20 ( a space ) for search query strings. Since then it has been updated and now creates a problem since I need the literal plus sign. I am going to see if there is a way to just replace its encoding back to %2B. If you’ve got any insight or a work around that would be much appreciated! . Thank you again!

        Reply
        • Steven Duque says

          October 15, 2015 at 7:54 am

          SO It was an easy fix. Just do a string.replace on the spaces and put +’s there. However my final error is “Invalid Token” . The result.Succeeded from the ConfirmEmailAsync comes back false. I placed breakpoints in the Register method and the ConfirmEmail method to verify the userId and code generated at both spots. They are identical. I’m not exactly sure what is going on at this point.

          Reply
          • Steven Duque says

            October 15, 2015 at 11:55 am

            FIXED! Sorry for the various replies but it’s been an interesting journey haha. SO seems like even if I do the string.replace in the frontend, when I do the $http call to the backend angular re-encodes and decodes it. Easy solution. Just do the code = code.replace(” “,”+”); right before calling ConfirmEmailAsync();
            THANK YOU for all your help!

          • Taiseer Joudeh says

            October 21, 2015 at 11:29 am

            Hi Steven,
            It is encoding issue as you suggested, I do not know why the ASP.NET team didn’t generate the confirmation code using safe URL characters, they know that those codes will be transmitted in URL.

  23. Khalaf says

    October 23, 2015 at 7:22 am

    Hi Taiseer,
    I keep getting this error when I run it locally , could you please advise?
    FYI I added the below keys which are valid:

    exceptionMessage: “Bad Request Check Errors for a list of errors returned by the API.”
    exceptionType: “Exceptions.InvalidApiRequestException”
    stackTrace: ” at SendGrid.ErrorChecker.CheckForErrors(HttpResponseMessage response, Stream stream) at SendGrid.ErrorChecker.d__0.MoveNext() — End of stack trace from previous location where exception was thrown — at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at SendGrid.Web.d__0.MoveNext() — End of stack trace from previous location where exception was thrown — at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at AspNetIdentity.Services.EmailService.d__1.MoveNext() in c:\users\armaghanbabak\documents\visual studio

    Reply
    • Taiseer Joudeh says

      October 26, 2015 at 10:45 am

      Hi Khalaf,
      Make sure you are using the latest version of SendGrid assembly, I’m not sure why it is generating this error. Please share it on Stack Overflow.

      Reply
  24. Biswa says

    October 27, 2015 at 3:41 pm

    Solved a lot of issues. This article is the masterpiece of all my research on ASP .NET Identity and OWIN Token.

    Reply
    • Taiseer Joudeh says

      October 31, 2015 at 2:45 am

      Glad you find it useful Biswa, thanks for your comment 🙂

      Reply
  25. hassan says

    November 5, 2015 at 10:49 pm

    Hi Taiseer,

    I have followed your part 1 tutorial, so far it has worked awesome, but in this part 2, you said place the code in ApplicationUserManager class, which you have not specified when it was created. I am looking your project in the GitHub and seeing you have Infrastructure folder and there you have it already, so I am trying to copy the code from there and trying to understand each bit of code. Please advice if I missed something.
    Thanks,
    Hassan

    Reply
    • Taiseer Joudeh says

      November 6, 2015 at 3:37 am

      Hi Hassan,
      I’m not sure if you missed something or I forgot a simple step but follow up with the all the posts and everything is described clearly, hope the series will be useful for you.

      Reply
      • hassan says

        November 6, 2015 at 6:06 pm

        Hi Taiseer,
        Sorry It was my mistake, I went to this Part 2 of ‘
        ASP.NET Identity 2.1 Accounts Confirmation, and Password Policy Configuration – Part 2’, thought that this is a Part 2 of ‘Token Based Authentication using ASP.NET Web API 2, Owin, and Identity’. But I have finally found the Part 2 here https://bitoftech.net/2014/06/09/angularjs-token-authentication-using-asp-net-web-api-2-owin-asp-net-identity/

        Got confused with so many parts of authentication. This is fabulous article you have written, I am following and understanding the authentication much better now. Thanks a lot man.

        Reply
        • Taiseer Joudeh says

          November 11, 2015 at 6:55 pm

          You are welcome, hope you grasped the concepts by now 🙂

          Reply
        • Neil says

          January 6, 2016 at 9:59 pm

          Same thing happened to me. Exact same thing.

          Reply
  26. Saad Ullah Khan says

    November 23, 2015 at 4:03 am

    For anyone who might run in to this kind of issue that if you are using different attributes than just [Route] or [HttpGet]… On confirmEmail action you must put the attribute [HttpGet] as well.. otherwise your link to confirm email won’t work ..

    Not sure why, may be Taiseer could add something awesome here on this just like his articles 🙂

    Hey Taiseer, Very useful articles, specially in a world where there aren’t much resources on the subject of identity … Hats off my dear !!!

    Reply
    • Taiseer Joudeh says

      November 24, 2015 at 1:33 pm

      Hi Saad, thanks for your message, it is working at my end. But I need to check this and update the post if something is missing. Thanks again.

      Reply
  27. Aditya M S K says

    December 21, 2015 at 3:54 pm

    Hi Taiseer,

    Thanks for the way you have narrated the story. I stand at a little confused point and need your help in getting out of this. it is a bit lengthy one, request you to go through it patiently. Thanks for your time.

    I work on an application where I have a separate MVC layer and Web API Layer, both have the same authentication mechanism, I have chosen the individual accounts authentication option while adding the projects. The web api service layer will be directly accessed by some other mobile clients also.

    But when the user logs in through MVC he should be able to access Web Api seamlessly, but I don’t want to really pass the username and password fro MVC to the Web Api layer, I am told it is a bad practice. but i need to authenticate and authorize my user, so the only option i have thought of is to have a default account at Web API level to issue tokens, and this will be called from MVC post the authentication and a token will be returned which is written to a cookie in the client. Now the Ajax calls from the UI can use this bearer token and get the job done.

    The only glitch I have here is that, because I am using a default account I need user details again for authorization at service level, though I am doing authorization at my UI level. The user can spoof the system. I was lost here and came up with a solution like, when the user logs in to MVC will send across user details also along with the call to get the WebAPI token and issue another token to the user so that the user uses both of the tokens to make a call to web api from MVC.

    I am not sure if this works or if it is even the best way. I just wanted to check with you, how I should go from here. Any help on this will be really great.

    Regards,
    Aditya

    Reply
    • Taiseer Joudeh says

      December 24, 2015 at 2:57 am

      Your proposed solution is good, you need to obtain an access token while you are authenticating the user for the MVC application, so you only send the username/password only once, once you obtain the access token you can store in a cookie for further use.

      Reply
  28. Rashmi says

    December 28, 2015 at 8:18 pm

    Hi Taiseer,

    First of all, this article is AWESOME. I am able to get a clear view of OAuth Identity Services because of your articles. I created the confirm email functionality for new User. The confirm email link validity is set to 24 hours as shown in this article, but somehow the link expires after 50 mins. I am unable to figure out where the issue is. Could you please suggest something.
    Regards,
    Rashmi

    Reply
    • Rashmi says

      January 7, 2016 at 12:03 am

      I found the solution to this issue. I am posting it if somebody faced the same issue. In my case the services and web API were on different servers. Different machine keys caused this issue. So I generated the machine key for my Web application and posted the same machine key in web.config file of Identity service. After that it worked. For more information on generating machine key, following link is helpful.
      http://gunaatita.com/Blog/How-to-Generate-Machine-Key-using-IIS/1058

      Reply
  29. onefootswill says

    January 7, 2016 at 4:41 am

    The confusion around ApplicationUserManager is because it was not created in Part 1. According to the Index at the top of this post, this is Part 2. And up until now, there has been no mention of an ApplicationUserManager. But, seeing that it is in the GIT repository, I’m not too worried. But it does kind of negatively impact the didactic flow of the articles.

    Reply
  30. onefootswill says

    January 7, 2016 at 5:30 am

    Whoops. Looks like I’m getting this series mixed up with your 2014 series of articles. Sorry. Disregard my last comment. And thank you for the great articles!

    Reply
    • Taiseer Joudeh says

      January 10, 2016 at 1:23 am

      You are welcome, no problem and let me know if you need further help.

      Reply
  31. RR says

    January 8, 2016 at 3:08 am

    Easily, the best posts on asp.net Identity on the ‘Net. Puts Microsoft documentation to shame.
    Congratulations !

    Reply
    • Taiseer Joudeh says

      January 10, 2016 at 1:23 am

      Thank you, happy that posts are helpful.

      Reply
  32. alexstrakh says

    January 11, 2016 at 9:59 am

    Thank you for the great post. In my case I need to validate both email and phone number for one given account.
    I can generate email token with GenerateEmailConfirmationTokenAsync and then ConfirmEmailAsync.
    I didn’t find related methods for SMS.

    Could you please clarify?

    Reply
  33. Dennis Guthrie says

    January 24, 2016 at 10:20 pm

    Taiseer….awesome series. Everything working perfectly. Your tutorials are extremely clear and accurate. Very rare. I do have one issue….I am using SendGrid for my Email Confirmation. When I change EmailConfirmation to POST as you recommend for doing Password comparison, the link that arrives in the confirmation email is no longer functional since a link can’t generate HTTP POST without intervening JScript. I just get a ‘The requested resource does not support http method ‘GET” error. Can you give a little detail on how to implement the password check in the confirmation (including maybe some suggestions for encrypting it)?

    Reply
    • Taiseer Joudeh says

      January 27, 2016 at 8:11 am

      Hi Dennis,

      I think you facing an issue with sending the validation token generated by asp.net identity, it contains unsafe url chars, so you should encode it before sending it, then decode it once you receive it.

      The below helper functions might help:

      public static string Base64ForUrlEncode(string str)
      {
      byte[] encbuff = Encoding.UTF8.GetBytes(str);
      return TextEncodings.Base64Url.Encode(encbuff);
      }

      public static string Base64ForUrlDecode(string str)
      {
      byte[] decbuff = TextEncodings.Base64Url.Decode(str);
      return Encoding.UTF8.GetString(decbuff);
      }

      var callbackUrl = string.Format("{0}?code={1}&email={2}", model.RedirectUri, base64UrlEnCode, model.Email);

      string decodedCode = Base64ForUrlDecode(model.Code);

      Reply
      • Dennis Guthrie says

        January 31, 2016 at 9:34 pm

        Thanks for the reply. Unfortunately that has the same result.

        The resulting link from CreateUser looked like this:

        http://localhost/rcatshop/api/accounts/ConfirmEmail?userId=1007&code=XXX

        I can’t see anything bad about the format of the link.

        Here is my CreateUser:

        [Route(“create”)]
        public async Task CreateUser(CreateUserBindingModel createUserModel)
        {
        if (!ModelState.IsValid)
        {
        return BadRequest(ModelState);
        }

        var user = new ApplicationUser()
        {
        UserName = createUserModel.Username,
        Email = createUserModel.Email,
        FirstName = createUserModel.FirstName,
        LastName = createUserModel.LastName,
        Level = 3,
        JoinDate = DateTime.Now.Date,
        };

        IdentityResult addUserResult = await this.AppUserManager.CreateAsync(user, createUserModel.Password);

        if (!addUserResult.Succeeded)
        {
        return GetErrorResult(addUserResult);
        }

        // Generate confirmation token
        string code = await this.AppUserManager.GenerateEmailConfirmationTokenAsync(user.Id);

        // Create link for “click on this to confirm”

        var callbackUrl = new Uri(Url.Link(“ConfirmEmailRoute”, new { userId = user.Id, code = UrlEncodeDecode.Base64ForUrlEncode(code), password = UrlEncodeDecode.Base64ForUrlEncode(createUserModel.Password) }));

        // Send the confirmation email
        await this.AppUserManager.SendEmailAsync(user.Id, “Confirm your account”, “Please confirm your account by clicking here“);

        Uri locationHeader = new Uri(Url.Link(“GetUserById”, new { id = user.Id }));

        return Created(locationHeader, TheModelFactory.Create(user));
        }

        Here is the text of the email I receive:

        Please confirm your account by clicking here

        Here is my Confirm endpoint:

        [HttpPost]
        [Route(“ConfirmEmail”, Name = “ConfirmEmailRoute”)]
        public async Task ConfirmEmail(int userId, string code = “”, string password = “”)
        {
        string cd = UrlEncodeDecode.Base64ForUrlDecode(code);
        string pw = UrlEncodeDecode.Base64ForUrlDecode(password);
        if (userId == null || string.IsNullOrWhiteSpace(cd) || string.IsNullOrWhiteSpace(pw))
        {
        ModelState.AddModelError(“”, “User Id, Code, and Password are required”);
        return BadRequest(ModelState);
        }

        var temp = await this.AppUserManager.FindByIdAsync(userId);
        bool PasswordOk = false;

        if (temp != null)
        {
        PasswordOk = await this.AppUserManager.CheckPasswordAsync(temp, pw);
        }
        if (PasswordOk)
        {
        IdentityResult result = await this.AppUserManager.ConfirmEmailAsync(userId, cd);

        if (result.Succeeded)
        {
        return Ok();
        }
        else
        {
        return GetErrorResult(result);
        }
        }
        else
        {
        return StatusCode(System.Net.HttpStatusCode.Unauthorized);
        }
        }

        And here is the result when I click the link from my email:

        The requested resource does not support http method ‘GET’.

        As long as I decorate the Confirm as:

        [HttpGet]
        [Route(“ConfirmEmail”, Name = “ConfirmEmailRoute”)]
        public async Task ConfirmEmail(int userId, string code = “”, string password = “”)

        All works. But as you stated in your tutorial, shouldn’t pass a password in a get param.

        I am not clear how to get around this.

        Is there something else I have missed?

        Thanks!

        Reply
  34. syedumair (@Engineerumair3) says

    February 14, 2016 at 5:50 pm

    @tauseer joudeh It is great article but I have one problem after email confirmation I want to redirect user to login page how that could be done please suggest?

    Reply
  35. engineerumairshah says

    February 21, 2016 at 6:57 pm

    @taiseer joudeh its very nice article could you please help me if I would like to change callbackurl from web api route to angular how could be done ?

    Reply
    • Taiseer Joudeh says

      February 22, 2016 at 11:42 am

      Hi,
      This is very deep implementation detail for your case, I really can not look at it right now but you could add any link you want in your response and the user will receive it in the email and click on it and get redirected to this URL.

      Reply
  36. stt106 says

    March 20, 2016 at 7:56 pm

    Hi Taiseer,

    Like others I have found your series on web api identity and token authorization very useful.

    I have a question about using email/text to validate the user identity. I am writing an API for a mobile app; on registration user will need either to enter email or mobile number so that their identity can be verified. Since sending email/text message to user is not free, I want to protect from being attached by someone who tries to create many fake registrations. For example, if someone somehow knows my user registration url and since user post request has to allow anonymous (to allow real user to register through the mobile app); he/she can post many fake registrations each of which will trigger sending an email or a text message; which can be costly.

    Do you have any advice on preventing such an attack? My idea is to add a custom header in my new user post request so that I can validate this header value in each post request and if the header value is not matching a secret then I will reject the post request. And since this is for a mobile app, it’s safe to include the secret in the header on the client side for real user registration. Does this make sense?
    Thanks.

    Reply
    • Taiseer Joudeh says

      March 20, 2016 at 11:35 pm

      Maybe you need to implement some sort of throttling (rate limiting) for this endpoint, check out this repo, I think it will be better than building thing from scratch.

      Reply
  37. Markus Kollers says

    March 25, 2016 at 1:30 am

    Hi Taiseer,

    i really love your articles! They help me soooooo much, but i still got a problem 🙁

    The Destination of IdentityMessage in my EmailService is always null. So i tried to get the email of the newly created user, and “UserManager.GetEmail” always returns null too, but the user is created as i can see in the database and his id is correct too. Do you have any idea what this can be, or do you had any issue like this before?

    Reply
    • Taiseer Joudeh says

      March 27, 2016 at 2:30 pm

      That is strange, did you try to download the repo and test it out and compare it to your code?
      Really hard to troubleshoot the issue without seeing your code, so my recommendation is to download the repo and compare.

      Reply
  38. Clifford Kwadwo Owusu says

    June 28, 2016 at 2:41 pm

    Hello,
    I am very much enjoying this tutorial. It is helping me with the understanding i have needed, but then i run into this error which i still can’t solve. I am still on the first post “account management” and i get this error:
    {“message”:”The request is invalid.”,”modelState”:{“”:[“Name cannot be null or empty.”]}}
    I do not know where to find the error to fix it.
    Please help me

    Reply
  39. Ali Reza shokoohmnad says

    July 12, 2016 at 7:46 pm

    hi … Thanks for the wonderful education.
    I am EmailService class to using Gmail instead of Sendgrid have changed.But I could not get the answer. Please help me to fix the error.

    using Microsoft.AspNet.Identity;
    using System.Net;
    using System.Net.Mail;
    using System.Threading.Tasks;

    namespace Myapp.Services
    {
    public class EmailService : IIdentityMessageService
    {
    public async Task SendAsync(IdentityMessage message)
    {
    await configSendasync(message);
    }
    // Use NuGet to install SendGrid (Basic C# client lib)
    private async Task configSendasync(IdentityMessage message)
    {
    using (MailMessage email = new MailMessage())
    {
    string emailFrom = “xxxx@gmail.com”;
    string password = “xxxxx”;
    // Create the message:
    email.From = new MailAddress(emailFrom,”email sender”);
    email.To.Add(new MailAddress(message.Destination));
    email.BodyEncoding = System.Text.Encoding.UTF8;
    email.SubjectEncoding = System.Text.Encoding.UTF8;
    email.Subject = message.Subject;
    email.Body = message.Body;
    email.IsBodyHtml = true;
    // Can set to false, if you are sending pure text.
    //email.Attachments.Add(new Attachment(“C:\\SomeFile.txt”));
    //email.Attachments.Add(new Attachment(“C:\\SomeZip.zip”));

    using (SmtpClient smtp = new SmtpClient())
    {
    // Configure the client:
    // Credentials:
    smtp.Host = “smtp.gmail.com”;
    //TLS port: 25, 587
    //SSL port:465
    smtp.Port = 25;
    // Create the credentials:
    smtp.Credentials = new NetworkCredential(emailFrom, password);
    smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
    smtp.UseDefaultCredentials = false;
    smtp.EnableSsl = true;
    //smtp.Send(email);
    // Send:
    await smtp.SendMailAsync(email);
    }
    }
    }
    }
    }

    Reply
  40. Ninh says

    July 14, 2016 at 6:04 am

    Hi,
    At that time I do this tutorial, I used Web API v2 and Net Framework 4.5. I need install SendGrid-Net40 instead of SendGrid.
    SendGrid does not have SendGridMessage Class.

    Reply
    • clark says

      July 18, 2016 at 12:56 pm

      Hi Ninh,

      Using Install-Package Sendgrid -Version 5.0.0

      Reply
      • hartmut says

        November 14, 2016 at 3:36 pm

        hey clark, you saved my day, thanks

        Reply
  41. Vladimir says

    July 22, 2016 at 11:21 pm

    Hello Taiser, great tutorials 🙂

    i get an error on
    applicationUserManager.cs

    appUserManager.EmailService = new AspNetIdentity.WebApi.Services.EmailService();

    Saying: The type or namespace name ‘AspNetIdentity’ could not be found (are you missing a using directive or an assembly reference?)

    Reply
    • Taiseer Joudeh says

      July 24, 2016 at 12:59 pm

      Hello Vlad,

      Make sure you are updating the packages using NuGet package manager, if this didn’t work please search the issue on GitHub as I’m sure you will find a detailed solution.

      Reply
    • Christophe Hvd says

      October 18, 2016 at 6:24 pm

      Hi Vladimir,
      Hope you already found the solution. If not, the problem is just that here Taiseer specifies the full namespace of the EmailService you created before. Just remove the “AspNetIdentity.WebApi.Services.” and it should work perfectly 😉

      Reply
  42. Fábio Jansen says

    October 21, 2016 at 11:32 am

    Hello friend.

    Thanks for the excellent article. Its saving my life.

    Im having problem with the username validation and UniqueEmail validation.

    I have added as you mentioned the :

    appUserManager.UserValidator = new MyCustomUserValidator(appUserManager)
    {
    AllowOnlyAlphanumericUserNames = true,
    RequireUniqueEmail = true
    };
    to my ApplicationUserManager class, but when i try to create a new user, its not being used.

    Im making some mistake?

    Thanks

    Reply
    • Taiseer Joudeh says

      October 28, 2016 at 3:20 pm

      Hello Fabio,
      Can you show me how did you register your AppUserManager there should be soemthing missing.

      Reply
  43. LK says

    March 9, 2017 at 1:32 am

    2 years later and this walk-through is still extremely helpful. Bravo and thank you!

    I’m new to API access security, so a few questions for you:

    1) When you mention changing the “ConfirmEmail” route to POST, could you elaborate on how this would be done? The only way I can fathom would be to send a link that leads to a webpage (something like http://www.mywebsite.com/validate?userid=xxxx&code=xxxx), where the user would then be prompted to enter the password that they just created for the account. This would effectively stop an unintended user from validating an account by accident, that they didn’t create.

    2) Seeing as these posts ARE 2 years old now, are there any major differences in implementation that you would recommend given the current state of the .NET Identity Framework?

    3) Would you still say that the .NET Identity Framework is one of the best ways to securely manage WebAPI access by today’s standards? I want to make sure I’m not implementing / familiarizing myself with something that has quickly fallen behind standard-wise.

    Reply
    • Taiseer Joudeh says

      March 11, 2017 at 1:14 pm

      Hello LK,
      Thanks for your kind comment 🙂
      Please find the answers below:
      1. If you need to have ultimate security workflow, asking for the password is a better approach, so you need to include the password when you validate the code and userid/password.
      2. If you are using ASP.NET 4.6 (Not ASP.NET Core) this post is very relevant, I believe I was using the latest version of ASP.NET Identity (2.1) which is used with ASP.NET 4.6
      3. Well the Identity framework is used to store your users, roles, claims, etc.. the OWIN middlewares for Authorization are used to protect your WebAPI, I recommend always to take a look at the ThinkTecture Identity Server if you want to learn something which is built on OAuth and OpenId connect standards and provides you SSO, support for multiple clients, etc..

      Reply
  44. S Rehman Ali says

    March 13, 2017 at 12:28 pm

    Hi,
    First of all awesome work helped me a lot!!

    Second there were some bugs since sendgrid is updated but i figure out error on this line

    var transportWeb = new Web(credentials);

    what is Web here i cant find its namespace

    Reply
    • Amir Attya says

      November 19, 2017 at 3:05 pm

      install old version 5.0.0 of sendgrid

      Reply
  45. Dima says

    June 6, 2017 at 10:04 pm

    Great series of articles! Thanks for it!

    Reply
    • Taiseer Joudeh says

      June 13, 2017 at 12:47 am

      You are welcome Dima 🙂

      Reply
  46. Kamal says

    July 8, 2017 at 5:56 am

    Hi do you have any tutorial of this implementation with MySQL

    Reply
  47. Sabiridwan says

    July 30, 2017 at 4:16 pm

    Hi please i need your help here. when ever i change user password with both

    var identityResult = await UserManager.ChangePasswordAsync(model.UserId, model.OldPassword, model.NewPassword);

    and this

    var token = await UserManager.GeneratePasswordResetTokenAsync(userId);
    var result = await UserManager.ResetPasswordAsync(userId, token, newPassword);

    the password do change successfully but i can’t login with the new password but the old password.
    the new password only work when i restart the application.

    i use this for login
    var user = await UserManager.FindAsync(userName, password);
    but return null when ever i change password

    here is my user manager

    public class ApplicationUserManager : UserManager
    {
    public ApplicationUserManager(IUserStore store)
    : base(store)
    {

    }

    public static ApplicationUserManager Create(IdentityFactoryOptions options,
    IOwinContext context)
    {
    var manager = new ApplicationUserManager(new UserStore(context.Get()));

    var dataProtectorProvider = options.DataProtectionProvider;
    var dataProtector = dataProtectorProvider.Create(“My Asp.Net Identity”);
    manager.UserTokenProvider = new DataProtectorTokenProvider(dataProtector)
    {
    TokenLifespan = TimeSpan.FromMinutes(30)
    };

    // Configure validation logic for usernames
    manager.UserValidator = new UserValidator(manager)
    {
    AllowOnlyAlphanumericUserNames = false,
    RequireUniqueEmail = true
    };

    // Configure validation logic for passwords
    manager.PasswordValidator = new PasswordValidator
    {
    RequiredLength = 6,
    RequireNonLetterOrDigit = false,
    RequireDigit = false,
    RequireLowercase = false,
    RequireUppercase = false
    };

    // Configure user lockout defaults
    manager.UserLockoutEnabledByDefault = false;
    manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
    manager.MaxFailedAccessAttemptsBeforeLockout = 5;

    manager.RegisterTwoFactorProvider(“Phone Code”, new PhoneNumberTokenProvider
    {
    MessageFormat = “Your security code is {0}”
    });
    manager.RegisterTwoFactorProvider(“Email Code”, new EmailTokenProvider
    {
    Subject = “Security Code”,
    BodyFormat = “Your security code is {0}”
    });
    //manager.EmailService = new EmailService();
    manager.SmsService = new SmsService();
    return manager;
    }

    }

    Reply
  48. station says

    August 30, 2017 at 8:59 pm

    Hоwdy, i read your blog from time to time and і own a similar one and
    i was just curious if уou get a lot of spam responses?
    If so how do you prevent it, any plugin or anything y᧐u can advise?
    I get so much lateⅼy it’s driving me insane so any ѕupport is νery mᥙch apprеciated.

    Reply
  49. success says

    September 2, 2017 at 11:33 am

    Ꭼxcellent web site. Lots of useful info here. I am sending
    it to a few buddies ans additionally sharing in delicious.
    And certainly, thanks on your sweat!

    Reply
  50. Li Yunhua says

    September 11, 2017 at 4:28 am

    Hi Taiseer
    I haven’t seen your new blog for a long time and look forward to sharing your new blog!

    Reply
  51. Kaditlehopper says

    September 14, 2017 at 3:44 pm

    ApplicationUser.Level is defined as byte, but the binding model defines it as int. The default value you are setting it to is 3 which is not valid for a byte. Please explain.

    Reply
    • Kaditlehopper says

      September 14, 2017 at 3:47 pm

      disregard this…byte, not bit. 🙂

      Reply
  52. Dat says

    October 2, 2017 at 10:00 pm

    Hi sir . What do you fill a code=xxxx ?. Thank you

    Reply
  53. multitapes says

    April 16, 2020 at 1:45 pm

    Good article

    Reply
  54. multitapes says

    April 22, 2020 at 5:26 pm

    thank you!

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About Taiseer

Husband, Father, Consultant @ MSFT, Life Time Learner... Read More…

Buy me a coffeeBuy me a coffee

Recent Posts

  • Integrate Azure AD B2C with ASP.NET MVC Web App – Part 3
  • Secure ASP.NET Web API 2 using Azure AD B2C – Part 2
  • Azure Active Directory B2C Overview and Policies Management – Part 1
  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
  • ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4

Blog Archives

Recent Posts

  • Integrate Azure AD B2C with ASP.NET MVC Web App – Part 3
  • Secure ASP.NET Web API 2 using Azure AD B2C – Part 2
  • Azure Active Directory B2C Overview and Policies Management – Part 1
  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5
  • ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4

Tags

AJAX AngularJS API API Versioning ASP.NET Authentication Autherization Server Azure Active Directory B2C Azure AD B2C basic authentication C# CacheCow Client Side Templating Code First Dependency Injection Entity Framework ETag Foursquare API HTTP Caching HTTP Verbs IMDB API IoC Javascript jQuery JSON JSON Web Tokens JWT Model Factory Ninject OAuth OData Pagination Resources Association Resource Server REST RESTful Single Page Applications SPA Token Authentication Tutorial Web API Web API 2 Web API Security Web Service wordpress.com

Search

Copyright © 2022 · eleven40 Pro Theme on Genesis Framework · WordPress · Log in

loading Cancel
Post was not sent - check your email addresses!
Email check failed, please try again
Sorry, your blog cannot share posts by email.