M.Tanzil
M.Tanzil

Reputation: 1995

Asp.net Core Email confirmation sometimes says InvalidToken

I am using asp.net core identity 2.1 and i am having a random issue with email confirmation, which while email confirmation sometimes says result.Error = InvalidToken. The token is also not expired.

Note: We are using multiple servers, and we have also stored our keys in one place so that all the servers use the same keys.

Code snippet for email confirmation.

Email Confirmation

var confCode = await _userManager.GenerateEmailConfirmationTokenAsync(user);
        var callbackUrl = Url.Action("ConfirmEmail", "Account", new
        {
            userId = user.Id,
            code = WebUtility.UrlEncode(confCode)
        }, protocol: HttpContext.Request.Scheme);

        string confirmationEmailBody = string.Format(GetTranslatedResourceString("ConfirmationEmailBody"), "<a href='" + callbackUrl + "'>") + "</a>";

Verification of token

public async Task<bool> ConfirmEmailAsync(string userId, string code)
    {
        if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(code))
            return false;


        var user = await _userManager.FindByIdAsync(userId);

        if (user == null)
            return false;

        var result = await _userManager.ConfirmEmailAsync(user, code).ConfigureAwait(false);

        if (!result.Succeeded)
            result = await _userManager.ConfirmEmailAsync(user, WebUtility.UrlDecode(code)).ConfigureAwait(false);

        return result.Succeeded;
    }

Invalid Token

The below token is encoded twice but we handle that situation

CfDJ8HYrrpCgcr5GvrItPOWapXRy8WF8odd%252BVKuDup7buRsl1x4agRpfgQlEIPWiBqM0Wuilu9tCv5l%252B3lNaAb89%252Fi%252B4k0y%252FH0jdXAbabz0%252FXDGA0eUrmcKdIsDFNuXeyP5ezTVmTx8t0ky9xCTXaKLAfvTsCJviETk5Ag9JbUs3l3%252BnUon6fyYOHsslJI5VKLqhMM0Sm%252BW1EE%252B%252FPEJ%252BXcn%252FPS1My%252BI1lExuF1R1hFEZScEsUCG%252Bx%252BVIFB9bzs1IoLC%252Baw%253D%253D

Any help will be appreciated, Thank you!

Upvotes: 17

Views: 2905

Answers (7)

avinash
avinash

Reputation: 183

If your encoded code contains '==' in the end. i.e after urlencode or base64 encode if the code comes out like this "cm9vdA==".

decoding this will not give you the exact encoded string and will result in an invalid code.

So while generating the token check if the encoded value ends with "==". If it does generate another token and the problem will be solved.

Upvotes: 0

Manoj Choudhari
Manoj Choudhari

Reputation: 5624

This problem seems to be basic Query String Related issue. There are no pointers in your question about sample expected value and sample actual value. Hence I will not be able to provide you exact answer here. But below two are the pointers which will certainly resolve this issue.

There can be two issues:

Issue 1: Original Base-64 is not restored after HtmlDecode/UrlDecode

These tokens are encoded as base 64 strings which may contain characters like '+'.

They are sent to server.

Then server tries to perform HtmlDecode operation on this string, to remove the characters which were actually present in original base 64 token.

E.g. '+' is replaced by empty string.

So, the token generated after WebUtility.HtmlDecode is invalid. That's why you get the invalid token error

How to check this ? You can debug and see what is the value after HtmlDecode and what is expected value. If they are differing then this is root cause.

Issue 2: Query string not correctly formed

Multiple key value pairs in query strings are joined using '&' character. e.g. key1=value1&key2=value2

But some times instead of & , its encoded version &amp; comes in the query string.
e.g. key1=value1&key2=value2

The .Net server would not be able to parse query string correctly if this is the case.

How to check this ? You can use directly read raw query string from HttpContext or HttpRequest using QueryString property and check if this is the case. If it is then you can either change your client to send appropriate query string (more logical and maintainable) or write some code to correct it on server side.

These pointers should help you to resolve the issue.

Upvotes: 4

tapos ghosh
tapos ghosh

Reputation: 2202

You do not need to solve this problem using identity server.

When a user register add two column in your user table. One for verification and others for IsVerified. In verification token column add a Guid. Then generate a link with this Guid. When a user clicks this link then you get the Guid inside a controller. Then get this user using this column, then set IsVerified column to true and delete your Guid column. And your user is now successfully verified.

Upvotes: 0

Jin Thakur
Jin Thakur

Reputation: 2773

I think the user creation process is taking too much time Before you are clicking confirm Make sure you check database that user is created Check confirm email is false in sql table

Upvotes: 0

Matt Schley
Matt Schley

Reputation: 227

You should decode the confirmation code prior to passing it into the _userManager.ConfirmEmailAsync(user, code).ConfigureAwait(false) method.

You have URL encoded the confirmation code that you use in the callBackUrl; you should use WebUtility.UrlDecode(code) to decode it before attempting to use it.

Upvotes: 0

hubert17
hubert17

Reputation: 304

This may not be the perfect answer, but if you just need an urgent fix and less headache, just generate a shorter disaster free token/code.

    services.AddIdentity<ApplicationUser, ApplicationRole>(options => {
        options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
        options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
    }).AddDefaultTokenProviders()
    .AddEntityFrameworkStores<YourDbContext>();

Upvotes: 0

Ahsan Iqbal
Ahsan Iqbal

Reputation: 3

your request for email conformation will gives you response as userId and Your Private key but your token method should be different function like token refresh, you need to add some conditions like if token has expired then refresh token

Upvotes: 0

Related Questions