Search code examples
angular.net-coretokenidentityserver4email-confirmation

Idenity.Core GenerateEmailConfirmationTokenAsync Invalid Token coming from Angular 10 WebApp


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.


Solution

  • 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);
            })
          );