{"title":"Signing notifications with HMAC","category":"Classic Platforms","creationDate":1680003120,"content":"<div class=\"sc-notice info\"><div>\n<p>This feature is supported from <a href=\"https:\/\/docs.adyen.com\/api-explorer\/#\/NotificationService\/v5\/overview\" class=\"codeLabel external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Notifications v5<\/a> and later.<\/p>\n<p>For information about platform integrations built after August 1, 2022, refer to our <a href=\"\/pt\/adyen-for-platforms-model\">new integration guide<\/a> instead.<\/p>\n<\/div><\/div>\n<p>By default, Adyen notifications use basic authentication. You can optionally enable\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Hash-based_message_authentication_code\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Hash-based Message Authentication Code (HMAC)<\/a>\u00a0signatures, which adds an extra layer of security to your <a href=\"\/pt\/development-resources\/webhooks\/webhook-types#other-webhooks\">standard notifications<\/a>.\u00a0<\/p>\n<p>An HMAC signature is calculated using a request's key-value pairs and a secret key, which is known only to you and the Adyen payments platform. By verifying this signature, you'll confirm that the notification was not modified during transmission.<\/p>\n<h2 id=\"enable-hmac-signatures\">Enable HMAC signatures<\/h2>\n<p>You can use any\u00a0<strong>32bit hexadecimal<\/strong>\u00a0HMAC key you like. If you subscribe to payment notifications you can reuse the same key. For more information, see\u00a0<a href=\"\/pt\/development-resources\/webhooks\/secure-webhooks\/verify-hmac-signatures\">Signing notifications with HMAC<\/a>.<\/p>\n<div class=\"sc-notice warning\"><div>\n<p>If you generate a new HMAC key, your previous notifications will still be signed with your previous HMAC key.<\/p>\n<\/div><\/div>\n<h2 id=\"subscribe-to-notifications\">Subscribe to notifications<\/h2>\n<p>Subscribe to notifications with a HMAC Signature Key to receive HMAC signed notifications to\u00a0the URL you specify in the\u00a0<code>\/createNotificationConfiguration<\/code>\u00a0call. We activate the <a href=\"https:\/\/docs.adyen.com\/api-explorer\/#\/NotificationService\/latest\/ACCOUNT_HOLDER_VERIFICATION\" class=\"codeLabel external-link no-image\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">ACCOUNT_HOLDER_VERIFICATION<\/a> notification and send it to the endpoint on your server (https&#58;\/\/www.merchant-domain.com\/notification-handler)\u00a0using the specified connection credentials (<span translate=\"no\"><strong>testUserName<\/strong><\/span>\u00a0and\u00a0<span translate=\"no\"><strong>testPassword<\/strong><\/span>).<\/p>\n<div data-component-wrapper=\"code-sample\">\n    <code-sample :title=\"'Create notification configuration'\" :id=\"'request'\" :code-data=\"[{&quot;language&quot;:&quot;bash&quot;,&quot;tabTitle&quot;:&quot;&quot;,&quot;content&quot;:&quot;curl https:\\\/\\\/cal-test.adyen.com\\\/cal\\\/services\\\/Notification\\\/v6\\\/createNotificationConfiguration \\\\\\n-H 'x-api-key: ADYEN_API_KEY' \\\\\\n-H 'content-type: application\\\/json' \\\\\\n-d '{\\n   \\&quot;configurationDetails\\&quot;:{\\n      \\&quot;active\\&quot;:true,\\n      \\&quot;apiVersion\\&quot;:6,\\n      \\&quot;description\\&quot;:\\&quot;Your unique description\\&quot;,\\n      \\&quot;eventConfigs\\&quot;:[\\n         {\\n            \\&quot;eventType\\&quot;:\\&quot;ACCOUNT_CREATED\\&quot;,\\n            \\&quot;includeMode\\&quot;:\\&quot;INCLUDE\\&quot;\\n         }\\n      ],\\n      \\&quot;hmacSignatureKey\\&quot;:\\&quot;79A3EAF309C43708726A8C284C0D72618696A12E840DFA1DF3A158AFA3B577DA\\&quot;,\\n      \\&quot;notifyPassword\\&quot;:\\&quot;password\\&quot;,\\n      \\&quot;notifyURL\\&quot;:\\&quot;https:\\\/\\\/www.merchant-domain.com\\\/notification-handler\\&quot;,\\n      \\&quot;notifyUsername\\&quot;:\\&quot;yourUsername\\&quot;\\n   }\\n}'&quot;}]\" :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<div data-component-wrapper=\"code-sample\">\n    <code-sample :title=\"'Response'\" :id=\"''\" :code-data='[{\"language\":\"json\",\"tabTitle\":\"\",\"content\":\"{\\n    \\\"pspReference\\\": \\\"8515658977098901\\\",\\n    \\\"configurationDetails\\\": {\\n        \\\"active\\\": true,\\n        \\\"apiVersion\\\": 6,\\n        \\\"description\\\": \\\"Your unique description\\\",\\n        \\\"eventConfigs\\\": [\\n            {\\n                \\\"eventType\\\": \\\"ACCOUNT_CREATED\\\",\\n                \\\"includeMode\\\": \\\"INCLUDE\\\"\\n            }\\n        ],\\n        \\\"notificationId\\\": 20271,\\n        \\\"notifyURL\\\": \\\"https:\\\/\\\/www.merchant-domain.com\\\/notification-handler\\\",\\n        \\\"sslProtocol\\\": \\\"SSLInsecureCiphers\\\"\\n    }\\n}\"}]' :enable-copy-link-to-code-block=\"true\" :code-sample-card-size=\"'fullsize'\"><\/code-sample>\n<\/div>\n<h2 id=\"verify-hmac-signature\">Verify HMAC signature<\/h2>\n<p>To verify the signature, retrieve the\u00a0values of the\u00a0<code>HmacSignature<\/code>\u00a0and\u00a0<code>Protocol<\/code> parameters from the HTTP header of the incoming notification<em>.<\/em>\u00a0<code>HmacSignature<\/code> contains the signature itself and\u00a0<code>Protocol<\/code> is the protocol used to create the signature (only SHA256 is supported).<\/p>\n<p>To compute the HMAC signature, apply the algorithm\/protocol to the whole HTTP body using the key. If the computed HMAC signature is equal to the one in the header, the verification is successful.<\/p>\n<div class=\"sc-notice note\"><div>\n<p>Perform this check before deserializing\u00a0the request. If you perform deserialization before verifying, a valid signature may fail due to a different order of the JSON elements\u00a0<\/p>\n<\/div><\/div>\n<h2 id=\"hmac-signature-examples\">HMAC signature examples<\/h2>\n<p>To calculate the HMAC signature:<\/p>\n<pre><code class=\"language-java\">import org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport javax.crypto.Mac;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.math.BigInteger;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Base64;\n\npublic class MarketplaceNotificationHmacExampleTest {\n\n    @Test\n    public void testMarketplaceNotificationHmac() {\n\n        \/\/ Example HEX Key (submitted at the moment of subscription)\n        String hmacSignatureKey = \"79A3EAF309C43708726A8C284C0D72618696A12E840DFA1DF3A158AFA3B577DA\";\n\n        \/\/ Signature. Retrieved from HTTP header under the name HmacSignature.\n        String hmacSignature = \"A2bHr0WPlKg1fJLVEDReVAdUDWt3znmsuYvp2KdihXY=\";\n\n        \/\/ Protocol. Retrieved from HTTP header under the name Protocol.\n        String protocol = \"HmacSHA256\";\n\n        \/\/ Payload. the payload of the notification consists on the whole body of the notification\n        String payload = \"{\\\"eventDate\\\":\\\"2018-07-09T12:07:27+02:00\\\",\\\"eventType\\\":\\\"ACCOUNT_HOLDER_CREATED\\\",\\\"executingUserKey\\\":\\\"ws\\\",\\\"live\\\":false,\\\"pspReference\\\":\\\"9915311308462016\\\",\"\n                + \"\\\"content\\\":{\\\"invalidFields\\\":[],\\\"pspReference\\\":\\\"9915311308462016\\\",\\\"accountCode\\\":\\\"9915311308462024\\\",\\\"accountHolderCode\\\":\\\"6750d8cf-80ab-4a34-b2c5-f8a1f37a79da\\\",\"\n                + \"\\\"accountHolderDetails\\\":{\\\"bankAccountDetails\\\":[],\\\"email\\\":\\\"testEmail@gmail.com\\\",\\\"individualDetails\\\":{\\\"name\\\":{\\\"firstName\\\":\\\"TestFirstName\\\",\\\"gender\\\":\\\"MALE\\\",\"\n                + \"\\\"lastName\\\":\\\"TestData\\\"}},\\\"merchantCategoryCode\\\":\\\"7999\\\"},\\\"accountHolderStatus\\\":{\\\"status\\\":\\\"Active\\\",\\\"processingState\\\":{\\\"disabled\\\":false,\"\n                + \"\\\"processedFrom\\\":{\\\"currency\\\":\\\"EUR\\\",\\\"value\\\":0},\\\"processedTo\\\":{\\\"currency\\\":\\\"EUR\\\",\\\"value\\\":0},\\\"tierNumber\\\":0},\\\"payoutState\\\":{\\\"allowPayout\\\":false,\"\n                + \"\\\"disabled\\\":false,\\\"tierNumber\\\":0},\\\"events\\\":[]},\\\"legalEntity\\\":\\\"Individual\\\",\\\"verification\\\":{}}}\";\n\n        try {\n\n            \/\/ decode HEX Key into bytes\n            byte[] keyBytes = new BigInteger(hmacSignatureKey, 16).toByteArray();\n\n            \/\/ get payload in bytes\n            byte[] payloadBytes = payload.getBytes(StandardCharsets.UTF_8);\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            \/\/ finalise the MAC operation\n            byte[] signedPayload = hmacSha256.doFinal(payloadBytes);\n\n            \/\/ encode the signed payload in Base64\n            byte[] encodedSignedPayload = Base64.getEncoder().encode(signedPayload);\n            System.out.println(\"original HMAC signature: \" + hmacSignature);\n            System.out.println(\"computed HMAC signature: \" + new String(encodedSignedPayload, StandardCharsets.US_ASCII));\n\n            \/\/ assert the calculated Base64 encoded HMAC is equal to the received Base64 encoded HMAC\n            Assertions.assertArrayEquals(encodedSignedPayload, hmacSignature.getBytes(StandardCharsets.UTF_8));\n\n        } catch (NoSuchAlgorithmException e) {\n            \/\/ HmacSHA256 should be supported\n        } catch (InvalidKeyException e) {\n            \/\/ The key is invalid\n        }\n    }\n}<\/code><\/pre>\n<p>If the calculated\u00a0<code>HmacSignature<\/code>\u00a0matches the value you received in the notification, the notification wasn't modified during transmission.<\/p>\n<p>The following is an example of a header containing an HMAC signature:<\/p>\n<pre><code class=\"language-bash\">[Content-Type: application\/json; charset=utf-8, Authorization: Basic dGVzdFVzZXJOYW1lOnRlc3RQYXNzd29yZA==, HmacSignature: awA4ZTCAYLp\/ctyt9yFPlidqZcLjWs5EZikhIQCz98k=, Protocol: HmacSHA256, Content-Length: 819, Host: localhost:57851, Connection: Keep-Alive, User-Agent: Adyen HttpClient 1.0, Accept-Encoding: gzip,deflate]<\/code><\/pre>\n<h2 id=\"see-also\">See also<\/h2>\n<div class=\"see-also-links output-inline\" id=\"see-also\">\n<ul><li><a href=\"\/classic-platforms\/configure-notifications\"\n                        target=\"_self\"\n                        >\n                    Configure notifications\n                <\/a><\/li><li><a href=\"\/classic-platforms\/notification-types\"\n                        target=\"_self\"\n                        >\n                    Notification types\n                <\/a><\/li><li><a href=\"https:\/\/en.wikipedia.org\/wiki\/HMAC\"\n                        target=\"_blank\"\n                         class=\"external\">\n                    HMAC\n                <\/a><\/li><\/ul><\/div>\n","url":"https:\/\/docs.adyen.com\/pt\/classic-platforms\/configure-notifications\/signing-notifications-with-hmac","articleFields":{"description":"Add an extra layer of security to the notifications sent by Adyen for Platforms.","search_category":"Classic Platforms","id":"39955002","type":"page","_expandable":{"operations":""},"status":"current","last_edit_on":"28-03-2023 13:32","feedback_component":true,"filters_component":false,"parameters":{"directoryPath":"\/classic-platforms"}},"algolia":{"url":"https:\/\/docs.adyen.com\/pt\/classic-platforms\/configure-notifications\/signing-notifications-with-hmac","title":"Signing notifications with HMAC","content":"\nThis feature is supported from Notifications v5 and later.\nFor information about platform integrations built after August 1, 2022, refer to our new integration guide instead.\n\nBy default, Adyen notifications use basic authentication. You can optionally enable\u00a0Hash-based Message Authentication Code (HMAC)\u00a0signatures, which adds an extra layer of security to your standard notifications.\u00a0\nAn HMAC signature is calculated using a request's key-value pairs and a secret key, which is known only to you and the Adyen payments platform. By verifying this signature, you'll confirm that the notification was not modified during transmission.\nEnable HMAC signatures\nYou can use any\u00a032bit hexadecimal\u00a0HMAC key you like. If you subscribe to payment notifications you can reuse the same key. For more information, see\u00a0Signing notifications with HMAC.\n\nIf you generate a new HMAC key, your previous notifications will still be signed with your previous HMAC key.\n\nSubscribe to notifications\nSubscribe to notifications with a HMAC Signature Key to receive HMAC signed notifications to\u00a0the URL you specify in the\u00a0\/createNotificationConfiguration\u00a0call. We activate the ACCOUNT_HOLDER_VERIFICATION notification and send it to the endpoint on your server (https&#58;\/\/www.merchant-domain.com\/notification-handler)\u00a0using the specified connection credentials (testUserName\u00a0and\u00a0testPassword).\n\n    \n\n\n    \n\nVerify HMAC signature\nTo verify the signature, retrieve the\u00a0values of the\u00a0HmacSignature\u00a0and\u00a0Protocol parameters from the HTTP header of the incoming notification.\u00a0HmacSignature contains the signature itself and\u00a0Protocol is the protocol used to create the signature (only SHA256 is supported).\nTo compute the HMAC signature, apply the algorithm\/protocol to the whole HTTP body using the key. If the computed HMAC signature is equal to the one in the header, the verification is successful.\n\nPerform this check before deserializing\u00a0the request. If you perform deserialization before verifying, a valid signature may fail due to a different order of the JSON elements\u00a0\n\nHMAC signature examples\nTo calculate the HMAC signature:\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\nimport javax.crypto.Mac;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.math.BigInteger;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Base64;\n\npublic class MarketplaceNotificationHmacExampleTest {\n\n    @Test\n    public void testMarketplaceNotificationHmac() {\n\n        \/\/ Example HEX Key (submitted at the moment of subscription)\n        String hmacSignatureKey = \"79A3EAF309C43708726A8C284C0D72618696A12E840DFA1DF3A158AFA3B577DA\";\n\n        \/\/ Signature. Retrieved from HTTP header under the name HmacSignature.\n        String hmacSignature = \"A2bHr0WPlKg1fJLVEDReVAdUDWt3znmsuYvp2KdihXY=\";\n\n        \/\/ Protocol. Retrieved from HTTP header under the name Protocol.\n        String protocol = \"HmacSHA256\";\n\n        \/\/ Payload. the payload of the notification consists on the whole body of the notification\n        String payload = \"{\\\"eventDate\\\":\\\"2018-07-09T12:07:27+02:00\\\",\\\"eventType\\\":\\\"ACCOUNT_HOLDER_CREATED\\\",\\\"executingUserKey\\\":\\\"ws\\\",\\\"live\\\":false,\\\"pspReference\\\":\\\"9915311308462016\\\",\"\n                + \"\\\"content\\\":{\\\"invalidFields\\\":[],\\\"pspReference\\\":\\\"9915311308462016\\\",\\\"accountCode\\\":\\\"9915311308462024\\\",\\\"accountHolderCode\\\":\\\"6750d8cf-80ab-4a34-b2c5-f8a1f37a79da\\\",\"\n                + \"\\\"accountHolderDetails\\\":{\\\"bankAccountDetails\\\":[],\\\"email\\\":\\\"testEmail@gmail.com\\\",\\\"individualDetails\\\":{\\\"name\\\":{\\\"firstName\\\":\\\"TestFirstName\\\",\\\"gender\\\":\\\"MALE\\\",\"\n                + \"\\\"lastName\\\":\\\"TestData\\\"}},\\\"merchantCategoryCode\\\":\\\"7999\\\"},\\\"accountHolderStatus\\\":{\\\"status\\\":\\\"Active\\\",\\\"processingState\\\":{\\\"disabled\\\":false,\"\n                + \"\\\"processedFrom\\\":{\\\"currency\\\":\\\"EUR\\\",\\\"value\\\":0},\\\"processedTo\\\":{\\\"currency\\\":\\\"EUR\\\",\\\"value\\\":0},\\\"tierNumber\\\":0},\\\"payoutState\\\":{\\\"allowPayout\\\":false,\"\n                + \"\\\"disabled\\\":false,\\\"tierNumber\\\":0},\\\"events\\\":[]},\\\"legalEntity\\\":\\\"Individual\\\",\\\"verification\\\":{}}}\";\n\n        try {\n\n            \/\/ decode HEX Key into bytes\n            byte[] keyBytes = new BigInteger(hmacSignatureKey, 16).toByteArray();\n\n            \/\/ get payload in bytes\n            byte[] payloadBytes = payload.getBytes(StandardCharsets.UTF_8);\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            \/\/ finalise the MAC operation\n            byte[] signedPayload = hmacSha256.doFinal(payloadBytes);\n\n            \/\/ encode the signed payload in Base64\n            byte[] encodedSignedPayload = Base64.getEncoder().encode(signedPayload);\n            System.out.println(\"original HMAC signature: \" + hmacSignature);\n            System.out.println(\"computed HMAC signature: \" + new String(encodedSignedPayload, StandardCharsets.US_ASCII));\n\n            \/\/ assert the calculated Base64 encoded HMAC is equal to the received Base64 encoded HMAC\n            Assertions.assertArrayEquals(encodedSignedPayload, hmacSignature.getBytes(StandardCharsets.UTF_8));\n\n        } catch (NoSuchAlgorithmException e) {\n            \/\/ HmacSHA256 should be supported\n        } catch (InvalidKeyException e) {\n            \/\/ The key is invalid\n        }\n    }\n}\nIf the calculated\u00a0HmacSignature\u00a0matches the value you received in the notification, the notification wasn't modified during transmission.\nThe following is an example of a header containing an HMAC signature:\n[Content-Type: application\/json; charset=utf-8, Authorization: Basic dGVzdFVzZXJOYW1lOnRlc3RQYXNzd29yZA==, HmacSignature: awA4ZTCAYLp\/ctyt9yFPlidqZcLjWs5EZikhIQCz98k=, Protocol: HmacSHA256, Content-Length: 819, Host: localhost:57851, Connection: Keep-Alive, User-Agent: Adyen HttpClient 1.0, Accept-Encoding: gzip,deflate]\nSee also\n\n\n                    Configure notifications\n                \n                    Notification types\n                \n                    HMAC\n                \n","type":"page","locale":"pt","boost":17,"hierarchy":{"lvl0":"Home","lvl1":"Classic integration","lvl2":"Configure notifications","lvl3":"Signing notifications with HMAC"},"hierarchy_url":{"lvl0":"https:\/\/docs.adyen.com\/pt","lvl1":"https:\/\/docs.adyen.com\/pt\/classic-platforms","lvl2":"https:\/\/docs.adyen.com\/pt\/classic-platforms\/configure-notifications","lvl3":"\/pt\/classic-platforms\/configure-notifications\/signing-notifications-with-hmac"},"levels":4,"category":"Classic Platforms","category_color":"green","tags":["Signing","notifications"]}}
