public async Task ClaimTokenAsync(string accountLinkingToken, string tenantId, string userId, string codeVerifier) { var(acctState, exp) = await _oAuthStateService.GetAsync(accountLinkingToken); // ensure the PKCE verifier is correct var codeGuess = Pkce.Base64UrlEncodeSha256(codeVerifier); if (!string.Equals(acctState.CodeChallenge, codeGuess, StringComparison.OrdinalIgnoreCase)) { _logger.LogWarning("PKCE verification failed:\nChallenge:{codeChallenge}\nVerifier:{verifier}\nH(Verifier):{guess}", acctState.CodeChallenge, codeVerifier, codeGuess); throw new Exception("PKCE code verification failed"); } // ensure this isn't a replay await _replayValidator.ClaimIdAsync(acctState.Id, exp); // Claim the oauth code from the downstream var oAuthResult = await _oAuthServiceClient.ClaimCodeAsync(acctState.OAuthCode); var dto = new OAuthUserTokenDto { AccessToken = oAuthResult.AccessToken, AccessTokenExpiration = DateTimeOffset.Now + TimeSpan.FromSeconds(oAuthResult.ExpiresInSeconds), RefreshToken = oAuthResult.RefreshToken }; var serializedDto = JsonSerializer.Serialize(dto); await _userTokenStore.SetTokenAsync(tenantId : tenantId, userId : userId, serializedDto); }