nopSolutions/nopCommerce · error · NopException

Hash validation failed

Error message

Hash validation failed

What it means

Thrown by FacebookDataDeletionController.DataDeletionCallback as a NopException when the HMAC-SHA256 of split[1] (the payload) computed with the app secret does not match the provided signature. This is the cryptographic integrity check for Facebook signed requests.

Source

Thrown at src/Plugins/Nop.Plugin.ExternalAuth.Facebook/Controllers/FacebookDataDeletionController.cs:85

        {
            string signed_request = form["signed_request"];
            if (string.IsNullOrEmpty(signed_request))
                throw new NopException("Request data is missing");

            var split = signed_request.Split('.');
            var signatureRaw = DecodeUrlBase64(split[0]);
            var dataRaw = DecodeUrlBase64(split[1]);
            if (string.IsNullOrEmpty(signatureRaw) || string.IsNullOrEmpty(dataRaw))
                throw new NopException("Part of the request data is missing");

            var signature = Convert.FromBase64String(signatureRaw);
            var dataBuffer = Convert.FromBase64String(dataRaw);
            var json = Encoding.UTF8.GetString(dataBuffer);
            var appSecretBytes = Encoding.UTF8.GetBytes(_facebookExternalAuthSettings.ClientSecret);
            HMAC hmac = new HMACSHA256(appSecretBytes);
            var expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(split[1]));
            if (!expectedHash.SequenceEqual(signature))
                throw new NopException("Hash validation failed");

            var fbUser = JsonConvert.DeserializeObject<FacebookUserDTO>(json);
            var authenticationParameters = new ExternalAuthenticationParameters
            {
                ProviderSystemName = FacebookAuthenticationDefaults.SystemName,
                AccessToken = await HttpContext.GetTokenAsync(FacebookDefaults.AuthenticationScheme, "access_token"),
                ExternalIdentifier = fbUser.UserId
            };
            var externalAuthenticationRecord = await _externalAuthenticationService.GetExternalAuthenticationRecordByExternalAuthenticationParametersAsync(authenticationParameters);
            if (externalAuthenticationRecord is not null)
            {
                await _logger.InformationAsync($"{FacebookAuthenticationDefaults.SystemName} data deletion completed. " +
                                               $"CustomerId: {externalAuthenticationRecord.CustomerId}, " +
                                               $"CustomerEmail: {externalAuthenticationRecord.Email}, " +
                                               $"ExternalAuthenticationRecordId: {externalAuthenticationRecord.Id}");

                await _externalAuthenticationService.DeleteExternalAuthenticationRecordAsync(externalAuthenticationRecord);
            }

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Update _facebookExternalAuthSettings.ClientSecret to the current Facebook App Secret for the app that issued the callback.
  2. After rotating a Facebook app secret, immediately update the plugin configuration for all stores/environments.
  3. Confirm the request was not modified by a proxy (HTTPS termination, body rewriting).

Example fix

// before: ClientSecret is stale / from another app
// after: set current secret from developers.facebook.com > App Settings > Advanced
settings.ClientSecret = "<current app secret>";
await _settingService.SaveSettingAsync(settings, storeScope);
Defensive patterns

Strategy: validation

Validate before calling

var expected = new HMACSHA256(Encoding.UTF8.GetBytes(secret)).ComputeHash(Encoding.UTF8.GetBytes(payload));
if (!expected.SequenceEqual(signature))
    // secret mismatch — alert ops to rotate/update config

Try / catch

try { return await DataDeletionCallback(form); }
catch (NopException ex) when (ex.Message.Contains("Hash validation failed"))
{ logger.Error("Facebook signature mismatch — check app secret config.", ex); return Unauthorized(); }

Prevention

When it happens

Trigger: The signature in signed_request does not match HMAC-SHA256(payload, appSecret). Causes: the configured ClientSecret is wrong/different from the app that signed the request, the payload was tampered with, or the app has multiple secrets and the wrong one is configured.

Common situations: Rotated the Facebook app secret but did not update the plugin config; copied config from a different Facebook app; payload altered in transit; using the wrong environment's secret.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/fe8f767ad08632e6. Report an issue: GitHub.