{"title":"Verify HMAC signatures","category":"default","creationDate":1779533780,"content":"<p>To protect your server from unauthorised webhook events, we strongly recommend that you use <a href=\"https:\/\/en.wikipedia.org\/wiki\/HMAC\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Hash-based message authentication code<\/a> (HMAC) signatures for our webhooks that support it. For the ones that support <a href=\"#enable-hmac-signatures\">enabling HMAC signatures<\/a>, each webhook event will include a signature calculated using a secret HMAC key and a payload from the webhook. By verifying this signature, you confirm that the webhook was sent by Adyen, and was not modified during transmission.<\/p>\n<p>To verify HMAC signatures, you can either:<\/p>\n<ul>\n<li><a href=\"#verify-using-our-libraries\">Use one of our libraries<\/a>.<\/li>\n<li><a href=\"#verify-using-your-own-solution\">Build your own custom solution<\/a>.<\/li>\n<\/ul>\n<h2 id=\"enable-hmac-signatures\">Enable HMAC signatures<\/h2>\n<p>Each secret HMAC key is linked to one webhook endpoint. If you have multiple endpoints for receiving webhooks, generate an HMAC key for each of them.<\/p>\n<div class=\"notices green\">\n<p>You also need to generate a new HMAC key when you <a href=\"\/development-resources\/webhooks\/configure-and-manage#test-and-go-live\">switch from test to live<\/a>.<\/p>\n<\/div>\n<p>To start receiving HMAC signed webhooks, if the option is available:<\/p>\n<ol>\n<li>In your <a href=\"https:\/\/ca-test.adyen.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Customer Area<\/a>, go to <strong>Developers<\/strong> &gt; <strong>Webhooks<\/strong>.<\/li>\n<li>From the list of webhooks, select the one to configure.<\/li>\n<li>Select <strong>Edit webhook<\/strong> or the edit icon <i class=\"adl-icon-edit\"><\/i>.<\/li>\n<li>Under <strong>Security<\/strong>, generate a new HMAC key or enter an existing HMAC key.<br \/>\nIf you generate a new HMAC key, copy it and store it securely in your system.<\/li>\n<li>Select <strong>Save configuration<\/strong>.<\/li>\n<\/ol>\n<p>The HMAC key will now be used to sign webhook events that we send to your server.<\/p>\n<p>For our <a href=\"\/development-resources\/webhooks\/webhook-types\">Standard webhooks<\/a>, the signature is included in the <code>additionalData<\/code> field.<\/p>\n<p>For <a href=\"\/development-resources\/webhooks\/webhook-types#other-webhooks\">other types of webhooks<\/a>, although rare, the signature can be included in the request header. When the HMAC signature is included in the header, the steps to follow to verify the signature is different. See <a href=\"#verify-hmac-in-header\">Verify HMAC keys returned in the header<\/a>.<\/p>\n<pre><code class=\"language-json\">{\n   \"live\":\"false\",\n   \"notificationItems\":[\n      {\n         \"NotificationRequestItem\":{\n            \"additionalData\":{\n               \"hmacSignature\":\"+JWKfq4ynALK+FFzGgHnp1jSMQJMBJeb87dlph24sXw=\"\n            },\n          ...\n         }\n      }\n   ]\n}<\/code><\/pre>\n<h3>Changing your HMAC key<\/h3>\n<p>If you need to change the secret HMAC key used to sign webhook events, it is enough to <a href=\"\/development-resources\/webhooks\/secure-webhooks\/verify-hmac-signatures#enable-hmac-signatures\">generate a new HMAC key<\/a> in your <a href=\"https:\/\/ca-test.adyen.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Customer Area<\/a>.<\/p>\n<p>If you generate a new HMAC key, it can take some time to propagate this in our infrastructure, so make sure that you can still accept webhook events signed with your previous HMAC key for some time.<\/p>\n<h2 id=\"verify-using-our-libraries\">Verify using our libraries<\/h2>\n<p>You can verify HMAC signatures using Adyen's packaged HMAC validator libraries:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/Adyen\/adyen-java-api-library\/blob\/master\/src\/main\/java\/com\/adyen\/util\/HMACValidator.java\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Java library<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Adyen\/adyen-php-api-library\/blob\/9c351e93d0ac7000524f70f31c164f682dbf7492\/src\/Adyen\/Util\/HmacSignature.php\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">PHP library<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Adyen\/adyen-dotnet-api-library\/blob\/fc3301c13db828ac9d3ff4054eac2f4dcaecf208\/Adyen\/Util\/HMACValidator.cs\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">C# library<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Adyen\/adyen-node-api-library\/blob\/7e76d1b4c87d334f98a1ddc70b4e30a225244d2e\/src\/utils\/hmacValidator.ts\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">JavaScript library<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Adyen\/adyen-ruby-api-library\/blob\/develop\/lib\/adyen\/utils\/hmac_validator.rb\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Ruby Library<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Adyen\/adyen-python-api-library\/blob\/develop\/Adyen\/util.py\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Python Library<\/a><\/li>\n<\/ul>\n<div data-component-wrapper=\"code-sample\">\n    <code-sample :title=\"''\" :id=\"'hmac_validation'\" :code-data=\"[{&quot;language&quot;:&quot;java&quot;,&quot;tabTitle&quot;:&quot;Java&quot;,&quot;content&quot;:&quot;\\\/\\\/ YOUR_HMAC_KEY from the Customer Area\\nString hmacKey = \\&quot;YOUR_HMAC_KEY\\&quot;;\\n\\\/\\\/ Notification Request JSON\\nString notificationRequestJson = \\&quot;NOTIFICATION_REQUEST_JSON\\&quot;;\\nHMACValidator hmacValidator = new HMACValidator();\\nWebhookHandler webhookHandler = new WebhookHandler();\\nNotificationRequest notificationRequest = webhookHandler.handleNotificationJson(notificationRequestJson);\\n\\\/\\\/ Handle multiple notificationRequests\\nList&lt;NotificationRequestItem&gt; notificationRequestItems = notificationRequest.getNotificationItems();\\nfor ( NotificationRequestItem notificationRequestItem : notificationRequestItems ) {\\n    \\\/\\\/ Handle the notification\\n    if ( hmacValidator.validateHMAC(notificationRequestItem, hmacKey) ) {\\n        \\\/\\\/ Process the notification based on the eventCode\\n        String eventCode = notificationRequestItem.getEventCode();\\n    } else {\\n        \\\/\\\/ Non valid NotificationRequest\\n        System.out.print(\\&quot;Non valid NotificationRequest\\&quot;);\\n    }\\n}&quot;},{&quot;language&quot;:&quot;php&quot;,&quot;tabTitle&quot;:&quot;PHP&quot;,&quot;content&quot;:&quot;\\\/\\\/ YOUR_HMAC_KEY from the Customer Area\\n$hmacKey = \\&quot;YOUR_HMAC_KEY\\&quot;;\\n\\\/\\\/ Notification Request JSON\\n$jsonRequest = \\&quot;NOTIFICATION_REQUEST_JSON\\&quot;;\\n$notificationRequest = json_decode($jsonRequest, true);\\n$hmac = new \\\\Adyen\\\\Util\\\\HmacSignature();\\n\\\/\\\/ Handling multiple notificationRequests\\nforeach ( $notificationRequest[\\&quot;notificationItems\\&quot;] as $notificationRequestItem ) {\\n  $params = $notificationRequestItem[\\&quot;NotificationRequestItem\\&quot;];\\n  \\\/\\\/ Handle the notification\\n  if ( $hmac-&gt;isValidNotificationHMAC($hmacKey, $params) ) {\\n    \\\/\\\/ Process the notification based on the eventCode\\n    $eventcode = $params['eventCode'];\\n    print_r($eventcode);\\n  } else {\\n    \\\/\\\/ Non valid NotificationRequest\\n  }\\n}&quot;},{&quot;language&quot;:&quot;cs&quot;,&quot;tabTitle&quot;:&quot;C#&quot;,&quot;content&quot;:&quot;\\\/\\\/ YOUR_HMAC_KEY from the Customer Area\\nstring hmacKey = \\&quot;YOUR_HMAC_KEY\\&quot;;\\n\\\/\\\/ Notification Request JSON\\nstring notificationRequestJson = \\&quot;NOTIFICATION_REQUEST_JSON\\&quot;;\\nvar hmacValidator = new HmacValidator();\\nvar notificationHandler = new NotificationHandler();\\nvar handleNotificationRequest = notificationHandler.HandleNotificationRequest(notificationRequestJson);\\n\\\/\\\/ Handle multiple notificationRequests\\nList&lt;NotificationRequestItemContainer&gt; notificationRequestItemContainers = handleNotificationRequest.NotificationItemContainers;\\nforeach ( var notificationRequestItemContainer in notificationRequestItemContainers ) {\\n    var notificationItem = notificationRequestItemContainer.NotificationItem;\\n    \\\/\\\/ Handle the notification\\n    if ( hmacValidator.IsValidHmac(notificationItem, hmacKey) ) {\\n         \\\/\\\/ Process the notification based on the eventCode\\n        string eventCode = notificationItem.EventCode;\\n    } else {\\n        \\\/\\\/ Non valid NotificationRequest\\n    }\\n}&quot;},{&quot;language&quot;:&quot;js&quot;,&quot;tabTitle&quot;:&quot;NodeJS (JavaScript)&quot;,&quot;content&quot;:&quot;const { hmacValidator } = require('@adyen\\\/api-library');\\n\\\/\\\/ YOUR_HMAC_KEY from the Customer Area\\nconst hmacKey = \\&quot;YOUR_HMAC_KEY\\&quot;;\\nconst validator = new hmacValidator()\\n\\\/\\\/ Notification Request JSON\\nconst notificationRequest = NOTIFICATION_REQUEST_JSON;\\nconst notificationRequestItems = notificationRequest.notificationItems\\n\\\/\\\/ Handling multiple notificationRequests\\nnotificationRequestItems.forEach(function(notificationRequestItem) {\\n    \\\/\\\/ Get the notification\\n    const notification = notificationRequestItem.NotificationRequestItem\\n    \\\/\\\/ Handle the notification\\n    if( validator.validateHMAC(notification, hmacKey) ) {\\n        \\\/\\\/ Process the notification based on the eventCode\\n        const eventCode = notification.eventCode;\\n    } else {\\n        \\\/\\\/ Non valid NotificationRequest\\n        console.log(\\&quot;Non valid NotificationRequest\\&quot;);\\n    }\\n});&quot;}]\" :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<h2 id=\"verify-using-your-own-solution\">Verify using your own solution<\/h2>\n<p>To build your own solution for verifying HMAC signatures, follow these steps:<\/p>\n<h3 id=\"construct-the-payload\">Step 1: Construct the payload<\/h3>\n<div class=\"notices yellow\">\n<p>The values used below are from an <a href=\"#example\">example webhook<\/a>. To test your solution, replace the values with actual values that you receive in a webhook event.<\/p>\n<\/div>\n<p>Concatenate the following values from the webhook event, in the given order:<\/p>\n<table>\n<thead>\n<tr>\n<th>Key<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>pspReference<\/code><\/td>\n<td><strong>7914073381342284<\/strong><\/td>\n<\/tr>\n<tr>\n<td><code>originalReference<\/code><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td><code>merchantAccountCode<\/code><\/td>\n<td><span translate=\"no\"><strong>TestMerchant<\/strong><\/span><\/td>\n<\/tr>\n<tr>\n<td><code>merchantReference<\/code><\/td>\n<td><span translate=\"no\"><strong>TestPayment-1407325143704<\/strong><\/span><\/td>\n<\/tr>\n<tr>\n<td><code>value<\/code><\/td>\n<td><strong>1130<\/strong><\/td>\n<\/tr>\n<tr>\n<td><code>currency<\/code><\/td>\n<td><span translate=\"no\"><strong>EUR<\/strong><\/span><\/td>\n<\/tr>\n<tr>\n<td><code>eventCode<\/code><\/td>\n<td><span translate=\"no\"><strong>AUTHORISATION<\/strong><\/span><\/td>\n<\/tr>\n<tr>\n<td><code>success<\/code><\/td>\n<td><span translate=\"no\"><strong>true<\/strong><\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Assign an empty string to any fields that are empty, and use a colon (\":\") to delimit the values.<\/p>\n<p>For the above values, with an empty <code>originalReference<\/code>, you get:<\/p>\n<pre><code class=\"language-bash\">7914073381342284::TestMerchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true<\/code><\/pre>\n<h3 id=\"calculate-the-hmac-signature\">Step 2: Calculate the HMAC signature<\/h3>\n<div class=\"sc-notice info\"><div>\n<p>For <strong>hints<\/strong> about how to calculate the signature, have a look at the <a href=\"#verify-using-our-libraries\">library code samples<\/a> above.<\/p>\n<\/div><\/div>\n<ol>\n<li>\n<p>Convert the <a href=\"#construct-the-payload\">payload that you constructed<\/a> to a binary representation, given the UTF-8 charset.<\/p>\n<\/li>\n<li>\n<p>Convert the hexadecimal HMAC key that you <a href=\"\/development-resources\/webhooks\/secure-webhooks\/verify-hmac-signatures\/#enable-hmac-signatures\">generated in your Customer Area<\/a> from a hexadecimal string to a binary representation, given the UTF-8 charset.<\/p>\n<\/li>\n<li>\n<p>Calculate an HMAC using:<\/p>\n<ul>\n<li>The <a href=\"https:\/\/en.wikipedia.org\/wiki\/SHA-2\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">SHA256<\/a> function.<\/li>\n<li>The binary representation of the payload.<\/li>\n<li>The binary representation of the HMAC key.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>To get the final signature, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Base64\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Base64<\/a>-encode the result.<\/p>\n<\/li>\n<\/ol>\n<h3>Step 3: Compare signatures<\/h3>\n<p>If the signature that you calculated in <a href=\"#calculate-the-hmac-signature\">Step 2<\/a> matches the <code>hmacSignature<\/code> that you received, you'll know that the webhook event was sent by Adyen and was not modified during transmission.<\/p>\n<h3 id=\"example\">Example<\/h3>\n<p>Sample HMAC key:<\/p>\n<pre><code class=\"language-bash\">44782DEF547AAA06C910C43932B1EB0C71FC68D9D0C057550C48EC2ACF6BA056<\/code><\/pre>\n<p>Sample webhook event signed using the above HMAC key:<\/p>\n<pre><code class=\"language-json\">{\n   \"live\":\"false\",\n   \"notificationItems\":[\n      {\n         \"NotificationRequestItem\":{\n            \"additionalData\":{\n               \"hmacSignature\":\"coqCmt\/IZ4E3CzPvMY8zTjQVL5hYJUiBRg8UU+iCWo0=\"\n            },\n            \"amount\":{\n               \"value\":1130,\n               \"currency\":\"EUR\"\n            },\n            \"pspReference\":\"7914073381342284\",\n            \"eventCode\":\"AUTHORISATION\",\n            \"eventDate\":\"2019-05-06T17:15:34.121+02:00\",\n            \"merchantAccountCode\":\"TestMerchant\",\n            \"operations\":[\n               \"CANCEL\",\n               \"CAPTURE\",\n               \"REFUND\"\n            ],\n            \"merchantReference\":\"TestPayment-1407325143704\",\n            \"paymentMethod\":\"visa\",\n            \"success\":\"true\"\n         }\n      }\n   ]\n}<\/code><\/pre>\n<h2 id=\"verify-hmac-in-header\">Verify HMAC keys returned in the header<\/h2>\n<p>For non-standard webhooks, Adyen can sign the webhook with an HMAC signature in the request header, instead of including it in the <code>additionalData<\/code> field. If you enabled <a href=\"\/development-resources\/webhooks\/webhook-types#other-webhooks\">other webhooks<\/a> that follow this pattern, for example, the <span translate=\"no\"><strong>Recurring tokens life cycle events<\/strong><\/span> webhook, there are different steps to verify the HMAC signature.<\/p>\n<ol>\n<li>\n<p>For every webhook that you receive, get the values from the following headers:<\/p>\n<ul>\n<li><code>hmacsignature<\/code>: Contains the signature.<\/li>\n<li><code>protocol<\/code>: The protocol used to create the signature, <span translate=\"no\"><strong>HmacSHA256<\/strong><\/span>.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Calculate the signature using:<\/p>\n<ul>\n<li><a href=\"https:\/\/en.wikipedia.org\/wiki\/SHA-2\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">SHA256<\/a>.<\/li>\n<li>The binary representation of the payload.<\/li>\n<li>The binary representation of the HMAC key.<\/li>\n<li>Make sure that the request body is as it is&mdash;do not deserialize it.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>To get the final signature, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Base64\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Base64<\/a>-encode the result.<\/p>\n<\/li>\n<li>\n<p>Compare the <code>hmacsignature<\/code> received from the header and the calculated signature. If the signatures match, then the webhook was sent by Adyen and was not modified during transmission.<\/p>\n<\/li>\n<\/ol>\n<p>Below is an examples HMAC signature validation.<\/p>\n<div data-component-wrapper=\"code-sample\">\n    <code-sample :title=\"''\" :id=\"'hmac-validator-header'\" :code-data=\"[{&quot;language&quot;:&quot;java&quot;,&quot;tabTitle&quot;:&quot;Java&quot;,&quot;content&quot;:&quot;import java.io.UnsupportedEncodingException;\\nimport java.security.InvalidKeyException;\\nimport java.security.NoSuchAlgorithmException;\\nimport java.util.Arrays;\\nimport javax.crypto.Mac;\\nimport javax.crypto.SecretKey;\\nimport javax.crypto.spec.SecretKeySpec;\\nimport org.apache.commons.codec.DecoderException;\\nimport org.apache.commons.codec.binary.Base64;\\nimport org.apache.commons.codec.binary.Hex;\\nimport org.junit.Assert;\\nimport org.junit.Test;\\n\\npublic class NotificationHmacExampleTest {\\n\\n    @Test\\n    public void testNotificationHmac(){\\n\\n        Base64 base64 = new Base64();\\n        \\\/\\\/ Example HEX Key (submitted at the moment of subscription)\\n        String hmacSignatureKey = \\&quot;6D5BADA576A73109D879220DCB793FFD67DEF7AA18C74CCC0AB66FD87AC8AEEA\\&quot;;\\n\\n        \\\/\\\/ Signature: retrieved from HTTP header under the name HmacSignature.\\n        String hmacSignature = \\&quot;nvsZjQiHBuscSdtcA2cl1E+PSLJfgjPeRdd0pSaRiA0=\\&quot;;\\n\\n        \\\/\\\/ Protocol: retrieved from HTTP header under the name Protocol.\\n        String protocol = \\&quot;HmacSHA256\\&quot;;\\n\\n        \\\/\\\/ Payload: body of the notification\\n        String payload = \\&quot;{\\\\\\&quot;createdAt\\\\\\&quot;:\\\\\\&quot;2024-01-14T18:10:49+01:00\\\\\\&quot;,\\\\\\&quot;environment\\\\\\&quot;:\\\\\\&quot;test\\\\\\&quot;,\\\\\\&quot;type\\\\\\&quot;:\\\\\\&quot;recurring.token.disabled\\\\\\&quot;,\\\\\\&quot;data\\\\\\&quot;:{\\\\\\&quot;merchantAccount\\\\\\&quot;:\\\\\\&quot;YOUR_MERCHANT_ACCOUNT\\\\\\&quot;,\\\\\\&quot;shopperReference\\\\\\&quot;:\\\\\\&quot;YOUR_SHOPPER_REFERENCE\\\\\\&quot;,\\\\\\&quot;storedPaymentMethodId\\\\\\&quot;:\\\\\\&quot;M5N7TQ4TG5PFWR50\\\\\\&quot;,\\\\\\&quot;type\\\\\\&quot;:\\\\\\&quot;visa\\\\\\&quot;},\\\\\\&quot;eventId\\\\\\&quot;:\\\\\\&quot;QBQQ9DLNRHHKGK38\\\\\\&quot;}\\&quot;;\\n\\n        try {\\n\\n            \\\/\\\/ decode HEX Key into bytes\\n            byte[] keyBytes = Hex.decodeHex(hmacSignatureKey.toCharArray());\\n\\n            \\\/\\\/ get payload in bytes\\n            byte[] payloadBytes = payload.getBytes(\\&quot;UTF-8\\&quot;);\\n\\n            \\\/\\\/ instantiate the MAC object using HMAC \\\/ SHA256\\n            Mac hmacSha256 = Mac.getInstance(protocol);\\n\\n            \\\/\\\/ create a key object using the secret key and MAC object\\n            SecretKey secretKey = new SecretKeySpec(keyBytes, hmacSha256.getAlgorithm());\\n\\n            \\\/\\\/ initialise the MAC object\\n            hmacSha256.init(secretKey);\\n\\n            \\\/\\\/ finalize the MAC operation\\n            byte[] signedPayload = hmacSha256.doFinal(payloadBytes);\\n            \\\/\\\/ encode the signed payload in Base64\\n            byte[] encodedSignedPayload = base64.encode(signedPayload);\\n            System.out.println(\\&quot;original HMAC signature: \\&quot; + hmacSignature);\\n            System.out.println(\\&quot;computed HMAC signature: \\&quot; + new String(encodedSignedPayload, \\&quot;ASCII\\&quot;));\\n\\n            \\\/\\\/ assert the calculated Base64 encoded HMAC is equal to the received Base64 encoded HMAC\\n            Assert.assertTrue(Arrays.equals(encodedSignedPayload, hmacSignature.getBytes(\\&quot;UTF-8\\&quot;)));\\n\\n        } catch (NoSuchAlgorithmException e) {\\n            \\\/\\\/ HmacSHA256 should be supported\\n        } catch (UnsupportedEncodingException e) {\\n            \\\/\\\/ UTF-8 should be supported\\n        } catch (DecoderException e) {\\n            \\\/\\\/ Check key for odd number or characters outside of HEX (base16)\\n        } catch (InvalidKeyException e) {\\n            \\\/\\\/ The key is invalid\\n        }\\n    }\\n}&quot;},{&quot;language&quot;:&quot;py&quot;,&quot;tabTitle&quot;:&quot;Python&quot;,&quot;content&quot;:&quot;import hmac\\nimport hashlib\\nimport base64\\n\\ndef checkHmac(payload, hmac_key, hmac_sig):\\n  # payload is the request body as it is\\n  # hmac_key is the secret\\n  # hmac_sig is the signature from the header\\n  hmac_key = binascii.a2b_hex(hmac_key)\\n  # Calculate signature\\n  calculatedHmac = hmac.new(hmac_key, payload.encode('utf-8'), hashlib.sha256).digest()\\n  calculatedHmac_b64 = base64.b64encode(calculatedHmac)\\n\\n  receivedHmac_b64 = hmac_sig.encode('utf-8')\\n  validSignature = hmac.compare_digest(receivedHmac_b64, calculatedHmac_b64)\\n\\n  if not validSignature:\\n      print('HMAC is invalid: {} {}'.format(receivedHmac_b64, calculatedHmac_b64))\\n      return False\\n\\n  return True&quot;}]\" :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<h2>See also<\/h2>\n<div class=\"see-also-links output-inline\" id=\"see-also\">\n<ul><li><a href=\"\/development-resources\/webhooks\"\n                        target=\"_self\"\n                        >\n                    Webhooks\n                <\/a><\/li><\/ul><\/div>\n","url":"https:\/\/docs.adyen.com\/development-resources\/webhooks\/secure-webhooks\/verify-hmac-signatures","articleFields":{"description":"Verify the integrity of webhook events using HMAC signatures.","id":"25145452","type":"page","_expandable":{"operations":""},"status":"current","feedback_component":true,"filters_component":false,"page_id":"e13840ed-0812-4245-969f-25e212e45492","decision_tree":"[]"},"algolia":{"url":"https:\/\/docs.adyen.com\/development-resources\/webhooks\/secure-webhooks\/verify-hmac-signatures","title":"Verify HMAC signatures","content":"To protect your server from unauthorised webhook events, we strongly recommend that you use Hash-based message authentication code (HMAC) signatures for our webhooks that support it. For the ones that support enabling HMAC signatures, each webhook event will include a signature calculated using a secret HMAC key and a payload from the webhook. By verifying this signature, you confirm that the webhook was sent by Adyen, and was not modified during transmission.\nTo verify HMAC signatures, you can either:\n\nUse one of our libraries.\nBuild your own custom solution.\n\nEnable HMAC signatures\nEach secret HMAC key is linked to one webhook endpoint. If you have multiple endpoints for receiving webhooks, generate an HMAC key for each of them.\n\nYou also need to generate a new HMAC key when you switch from test to live.\n\nTo start receiving HMAC signed webhooks, if the option is available:\n\nIn your Customer Area, go to Developers &gt; Webhooks.\nFrom the list of webhooks, select the one to configure.\nSelect Edit webhook or the edit icon .\nUnder Security, generate a new HMAC key or enter an existing HMAC key.\nIf you generate a new HMAC key, copy it and store it securely in your system.\nSelect Save configuration.\n\nThe HMAC key will now be used to sign webhook events that we send to your server.\nFor our Standard webhooks, the signature is included in the additionalData field.\nFor other types of webhooks, although rare, the signature can be included in the request header. When the HMAC signature is included in the header, the steps to follow to verify the signature is different. See Verify HMAC keys returned in the header.\n{\n   \"live\":\"false\",\n   \"notificationItems\":[\n      {\n         \"NotificationRequestItem\":{\n            \"additionalData\":{\n               \"hmacSignature\":\"+JWKfq4ynALK+FFzGgHnp1jSMQJMBJeb87dlph24sXw=\"\n            },\n          ...\n         }\n      }\n   ]\n}\nChanging your HMAC key\nIf you need to change the secret HMAC key used to sign webhook events, it is enough to generate a new HMAC key in your Customer Area.\nIf you generate a new HMAC key, it can take some time to propagate this in our infrastructure, so make sure that you can still accept webhook events signed with your previous HMAC key for some time.\nVerify using our libraries\nYou can verify HMAC signatures using Adyen's packaged HMAC validator libraries:\n\nJava library\nPHP library\nC# library\nJavaScript library\nRuby Library\nPython Library\n\n\n    \n\nVerify using your own solution\nTo build your own solution for verifying HMAC signatures, follow these steps:\nStep 1: Construct the payload\n\nThe values used below are from an example webhook. To test your solution, replace the values with actual values that you receive in a webhook event.\n\nConcatenate the following values from the webhook event, in the given order:\n\n\n\nKey\nValue\n\n\n\n\npspReference\n7914073381342284\n\n\noriginalReference\n\n\n\nmerchantAccountCode\nTestMerchant\n\n\nmerchantReference\nTestPayment-1407325143704\n\n\nvalue\n1130\n\n\ncurrency\nEUR\n\n\neventCode\nAUTHORISATION\n\n\nsuccess\ntrue\n\n\n\nAssign an empty string to any fields that are empty, and use a colon (\":\") to delimit the values.\nFor the above values, with an empty originalReference, you get:\n7914073381342284::TestMerchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true\nStep 2: Calculate the HMAC signature\n\nFor hints about how to calculate the signature, have a look at the library code samples above.\n\n\n\nConvert the payload that you constructed to a binary representation, given the UTF-8 charset.\n\n\nConvert the hexadecimal HMAC key that you generated in your Customer Area from a hexadecimal string to a binary representation, given the UTF-8 charset.\n\n\nCalculate an HMAC using:\n\nThe SHA256 function.\nThe binary representation of the payload.\nThe binary representation of the HMAC key.\n\n\n\nTo get the final signature, Base64-encode the result.\n\n\nStep 3: Compare signatures\nIf the signature that you calculated in Step 2 matches the hmacSignature that you received, you'll know that the webhook event was sent by Adyen and was not modified during transmission.\nExample\nSample HMAC key:\n44782DEF547AAA06C910C43932B1EB0C71FC68D9D0C057550C48EC2ACF6BA056\nSample webhook event signed using the above HMAC key:\n{\n   \"live\":\"false\",\n   \"notificationItems\":[\n      {\n         \"NotificationRequestItem\":{\n            \"additionalData\":{\n               \"hmacSignature\":\"coqCmt\/IZ4E3CzPvMY8zTjQVL5hYJUiBRg8UU+iCWo0=\"\n            },\n            \"amount\":{\n               \"value\":1130,\n               \"currency\":\"EUR\"\n            },\n            \"pspReference\":\"7914073381342284\",\n            \"eventCode\":\"AUTHORISATION\",\n            \"eventDate\":\"2019-05-06T17:15:34.121+02:00\",\n            \"merchantAccountCode\":\"TestMerchant\",\n            \"operations\":[\n               \"CANCEL\",\n               \"CAPTURE\",\n               \"REFUND\"\n            ],\n            \"merchantReference\":\"TestPayment-1407325143704\",\n            \"paymentMethod\":\"visa\",\n            \"success\":\"true\"\n         }\n      }\n   ]\n}\nVerify HMAC keys returned in the header\nFor non-standard webhooks, Adyen can sign the webhook with an HMAC signature in the request header, instead of including it in the additionalData field. If you enabled other webhooks that follow this pattern, for example, the Recurring tokens life cycle events webhook, there are different steps to verify the HMAC signature.\n\n\nFor every webhook that you receive, get the values from the following headers:\n\nhmacsignature: Contains the signature.\nprotocol: The protocol used to create the signature, HmacSHA256.\n\n\n\nCalculate the signature using:\n\nSHA256.\nThe binary representation of the payload.\nThe binary representation of the HMAC key.\nMake sure that the request body is as it is&mdash;do not deserialize it.\n\n\n\nTo get the final signature, Base64-encode the result.\n\n\nCompare the hmacsignature received from the header and the calculated signature. If the signatures match, then the webhook was sent by Adyen and was not modified during transmission.\n\n\nBelow is an examples HMAC signature validation.\n\n    \n\nSee also\n\n\n                    Webhooks\n                \n","type":"page","locale":"en","boost":16,"hierarchy":{"lvl0":"Home","lvl1":"Development resources","lvl2":"Webhooks","lvl3":"Secure webhooks","lvl4":"Verify HMAC signatures"},"hierarchy_url":{"lvl0":"https:\/\/docs.adyen.com\/","lvl1":"https:\/\/docs.adyen.com\/development-resources","lvl2":"https:\/\/docs.adyen.com\/development-resources\/webhooks","lvl3":"https:\/\/docs.adyen.com\/development-resources\/webhooks\/secure-webhooks","lvl4":"\/development-resources\/webhooks\/secure-webhooks\/verify-hmac-signatures"},"levels":5,"category":"Development Resources","category_color":"green","tags":["Verify","signatures"]},"articleFiles":{"hmac_validation.js":"<p alt=\"\">hmac_validation.js<\/p>"}}
