Reputation: 1995
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
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
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 &
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
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
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
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
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
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