Search code examples
azureasp.net-coreemail-confirmation

Email verification code in app url (deployed on azure) not finding endpoint


I have .net core identity email verification endpoint setup like this:

/api/[controller]/{userId}/{emailVerificationCode} 

and I encoded it in registration endpoint with Uri. EscapeDataString (decoding with Uri. UnescapeDataString but that's irrelevant here). So when I get email and I click the link, locally I hit endpoint and can debug it, but after deploying to azure (web app resource group) I get this response:

The resource you are looking for has been removed, had its name changed,
or is temporarily unavailable.

When I shorten code to not contain any special characters (which are now encoded so they are for example %2F, %3D etc) endpoint is hit (but ofc token is invalid). Any idea what could be the case?


Solution

  • The code that is generated is Base64 encoded, and certain characters in Base64 are not allowed in the path segment of a URL by default, for security reasons, even when URL-encoded. While it's possible to change that, you should not, as the security concerns are valid, and you don't want to expose your app to exploits.

    Instead, you can simply let the code be part of the query string. The same vulnerabilities do not exist for the query string portion of a URL, and the characters will be allowed there. Alternatively, you can use a different type of code. The token providers used by Identity for things like email confirmation and password resets can be customized.

    Identity includes other token providers for the purposes of two-factor auth that you can switch out with, if you like. These use TOTP-based tokens (the 6-7 digit numbers you see all the time with 2FA). Or, you can create your own custom provider and handle it however you like. To change providers, you simply configure the Tokens member when setting up Identity:

    services.AddIdentity<ApplicationUser, IdentityRole>(o =>
    {
        // other options here like password reqs, etc.
        o.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
        o.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
        o.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    }
    

    The above will cause those three scenarios to generate tokens via EmailTokenProvider, which is one of the TOTP-based providers builtin.

    If you want to use a custom provider, you simply create a class that implements IUserTwoFactorTokenProvider<TUser> and register that:

    services.AddIdentity<ApplicationUser, IdentityRole>(o =>
    {
        ...
    })
    .AddTokenProvider<MyCustomTokenProvider<ApplicationUser>>("MyTokenProviderName");
    

    The string you use as the "name" is what you would use to assign it as a token provider in the previous code above, i.e.:

    o.Tokens.PasswordResetTokenProvider = "MyTokenProviderName";