-1

I have a DotNet Core WebApi that uses Identity Core to generate an Email confirmation token. When I generate the token and send it to my email address with the WebApi URL it works fine. When I send the ur?token=token to my email with the Angular Web app to make the AJAX call from the app I get an "Invalid Token" error. THe GET call from the Angular Service gets the QueryString and makes the AJAX call to the API -> "Invalid Token."

WebApi Code:

//I tried 
//var confirmationLink = Url.Content($"{this.Request.Scheme}://{siteUrl}{this.Request.PathBase}/Confirm?token={token}&email={appUser.Email}");
// And
var confirmationLink = Url.Content($"{this.Request.Scheme}://{siteUrl}{this.Request.PathBase}/Confirm?token={HttpUtility.UrlEncode(token)}&email={appUser.Email}");
SendEmail($"{model.FirstName} {model.LastName}", "Confirm your account", model.Email,
$"Please confirm your account by clicking {callback}");

Angular View

this.route.queryParams.subscribe(params => {
      this.email = params[emailKey];
      this.token = params[tokenKey];
    }); 

this.authenticationService.confirmEmail(this.email, this.token).subscribe(
            (result) => {
              this.emailMsg = 'Thank you for confirming your email. Please procced to login page.';
            },
            (err) => {
              this.emailMsg = 'Email confirmation link has expired or is invalid.';
            }
          );

Angular Service

return this.http.get<boolean>(`${environment.apiUrl}/authenticate/VerifyEmail?email=${email}&token=${token}`)
      .pipe(
        map((data: boolean) => {
          return data;
        }), catchError((error: HttpErrorResponse) => {
          return throwError(error);
        })
      );

In the Email Confirmation Endpoint I tried a few different things and none work.

var user = await _userManager.FindByEmailAsync(email);

if (user == null) {
    throw new InvalidOperationException();
}

var fix = token.Replace(' ', '+');
var emailConfirmationResultescapefix = await _userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(fix));

var emailConfirmationResulttest = await _userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(token));

var code = HttpUtility.UrlDecode(token);
var emailConfirmationResult = await _userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(code));

var urisescape = Uri.EscapeDataString(token);
var emailConfirmationResultescape = await _userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(urisescape));

var webUtil = WebUtility.UrlDecode(token);
var emailConfirmationResultweb = await _userManager.ConfirmEmailAsync(user, Uri.EscapeDataString(webUtil));

All of the different methods I tried to verify the token fail. They all have an invalid token. I tried using code compare to check if the token is indeed different and it's not for the first method. The token matches and I still get an invalid token.

JEuvin
  • 866
  • 1
  • 12
  • 31
  • Before sending the code from your server to Angular, encode it with HttpUtility.UrlEncode(token). No need to decode it when the token is send from Angular to your server – FolabiAhn Jan 11 '21 at 18:55
  • I already tried that as well. The first attempt to fix the token var fix = token.Replace(' ', '+'); gets me an identical token but I still get "Invalid Token". – JEuvin Jan 11 '21 at 20:09
  • Need an info, the token is sent from webApi to mail and from mail to your client app. In the client app the token is perfectly fine. But once you call the AJAX call with the same token, can you please verify the token on receiving webApi method. If its same can you try doing the verification directly from the client directly, just to know which exact url transition is causing the issue. _. .And i hope you are not doing any kind of extra custom encoding for the token for better security (except the URLEncode) – Nav Kumar V Jan 20 '21 at 02:22
  • I'm not doing anything fancy and I tried token=${encodeURIComponent(token)} in the Angular App. Somewhere in between the token is changing and not working correctly. If I send the email from WebApi with a return URL to the API endpoint it works fine. But from Angular it doesn't. Its driving me crazy. – JEuvin Jan 20 '21 at 03:02

3 Answers3

1

As per my understanding, you are encoding the token in WebApi only, but I would suggest while passing the token from Angular service encodes it using encodeURIComponent(). So your code should be something like below.

Angular Service:

return this.http.get<boolean>(`${environment.apiUrl}/authenticate/VerifyEmail?email=${email}&token=${encodeURIComponent(token)}`)
      .pipe(
        map((data: boolean) => {
          return data;
        }), catchError((error: HttpErrorResponse) => {
          return throwError(error);
        })
      );
Mahesh More
  • 821
  • 1
  • 8
  • 23
  • Mahesh, the problem is not the token. The token matches 100%. But I still get an error. I don't know what is causing this issue. I ready something about a machine key. Not sure if this rings any bells. – JEuvin Jan 19 '21 at 18:14
0

This sounds really stupid but for some reason after doing the following:

token = token.Replace(' ', '+');

Now the email verification works.

JEuvin
  • 866
  • 1
  • 12
  • 31
0

The tokens generated by ASP.NET Identity are not guaranteed to be URL-safe.

If you use Identity.UI packages then it handles URL-safety for you since version 3.x.

I usually do Base64UrlEncoder.Encode(token) and Base64UrlEncoder.Decode(token) in my code to resolve this issue. It gets rid of all the symbols that could ever cause issue in URL-s.

Base64UrlEncoder is from namespace Microsoft.IdentityModel.Tokens.