4
votes

I trying to confirm user's email using Asp.net Identity 2.0. As suggested by few blogs I've put machineKey in Web.Config file, so that Encryption and Decryption works on Azure website. Locally I'm unable to generate token. While trying to confirm (Token generated by my web api) using UserManager.ConfirmEmailAsync method I'm getting "Invalid Token". I tried UrlEncoding my code, but that didn't work. I cannot find enough help to resolve this issue.

Email generation code looks like this

  code = HttpUtility.UrlEncode(UserManager.GenerateEmailConfirmationToken(identityUser.Id));
 _logger.Info("Generate confiruation token: " + code);

 string link = model.ConfirmUrl + string.Format("?userId={0}&code={1}", HttpUtility.UrlEncode(identityUser.Id), code);
 Configuration.Services.GetTraceWriter().Info(Request, Category, "Account GenereatedLink: " + link);

 UserManager.SendEmail(identityUser.Id, "Contactbook confirmation", link);

Confirm email code

       IdentityResult idResult = await UserManager.ConfirmEmailAsync(userId, code);
        IHttpActionResult result = GetErrorResult(idResult);

Startup.auth.cs Code

app.CreatePerOwinContext(CBIndentityDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            AllowInsecureHttp = true
        };
        app.UseOAuthBearerTokens(OAuthOptions);

AuthorizationManager.cs

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var appDbContext = context.Get<CBIndentityDbContext>();
        var appUserManager = new ApplicationUserManager(new UserStore<IdentityUser>(appDbContext));

        // Configure validation logic for usernames
        appUserManager.UserValidator = new UserValidator<IdentityUser>(appUserManager)
        {
            AllowOnlyAlphanumericUserNames = true,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        appUserManager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 7,
            RequireDigit = false
        };

        appUserManager.EmailService = new ContactbookEmailService();

        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            appUserManager.UserTokenProvider = new DataProtectorTokenProvider<IdentityUser>(dataProtectionProvider.Create("ASP.NET Identity"))
            {
                //Code for email confirmation and reset password life time
                TokenLifespan = TimeSpan.FromHours(6)
            };
        }

        return appUserManager;
    }

Web.config

<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5.2" />
<machineKey decryptionKey="6F7DEAA44E5E06B6B7480B055FF39960D69AD32BCBB178EB" validationKey="17D85F8147CF02697D16B05726B9D68E473A3BF79EB79AE4E7EF8E84DA6CCC46BFFB975741DA4D1F37F0EF41651422A2745296BA953CE0370D4337E2900C2A18" validation="SHA1" decryption="Auto" />

Every thing works fine when I remove machineKey. I need to have machinKey so that EmailConfirmation works properly in Azure.

Thanks in advance.

2
same problem here, have you solved out?Giuseppe

2 Answers

0
votes

Sometime when token has "+" character, it converts into " " when it comes back to your server back and it could be a reason of invalid taken. I used below method to that stuff for me.

    private string SanitizeToken(string token)
    {
        return token.Trim().Replace(" ", "+");
    }

You can take a look of complete implementation at here.

0
votes

Apply encoding on "code" before sending it and use decoding as on confirmation "code".

 public static class UrlEncoding
{
    public static string Base64ForUrlEncode(this string str)
    {
        byte[] encbuff = Encoding.UTF8.GetBytes(str);
        return HttpServerUtility.UrlTokenEncode(encbuff);
    }

    public static string Base64ForUrlDecode(this string str)
    {
        byte[] decbuff = HttpServerUtility.UrlTokenDecode(str);
        return Encoding.UTF8.GetString(decbuff);
    }
}

Example:- Before sending: UrlEncoding.Base64ForUrlEncode(code) On confirmation: UrlEncoding.Base64ForUrlDecode(code)