--- title: "Protect with a library" description: "Use an Adyen GitHub library to protect local communications between your POS app and terminal." url: "https://docs.adyen.com/point-of-sale/design-your-integration/choose-your-architecture/local/protect-with-library" source_url: "https://docs.adyen.com/point-of-sale/design-your-integration/choose-your-architecture/local/protect-with-library.md" canonical: "https://docs.adyen.com/point-of-sale/design-your-integration/choose-your-architecture/local/protect-with-library" last_modified: "2021-06-17T09:45:00+02:00" language: "en" --- # Protect with a library Use an Adyen GitHub library to protect local communications between your POS app and terminal. [View source](/point-of-sale/design-your-integration/choose-your-architecture/local/protect-with-library.md) If your integration uses local communications, you need to protect your integration against [man-in-the-middle attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack), eavesdropping, and tampering. To help you with this, we provide GitHub libraries that: * Validate the terminal certificate, to confirm your POS app is communicating directly with an Adyen-supplied payment terminal. * Encrypt communications. This prevents intruders from reading the messages transmitted between the POS app and the terminal. These GitHub libraries work with Terminal API and are completely separate from the [classic libraries, which have been deprecated](/point-of-sale/classic-library-deprecation). ## Encrypt communications The available libraries are: * .NET - [adyen-dotnet-api-library](https://github.com/Adyen/adyen-dotnet-api-library) * Terminal API for iOS - [adyen-terminal-api-ios](https://github.com/Adyen/adyen-terminal-api-ios) * Java - [adyen-java-api-library](https://github.com/Adyen/adyen-java-api-library) * Node - [adyen-node-api-library](https://github.com/Adyen/adyen-node-api-library) The libraries will: * Serialize the request object to JSON and then encrypt and sign the request. * Send the request and receive the response. * Decrypt and deserialize the response and pass the content to the response object. Select a tab below for the Adyen GitHub library you want to use. ### Tab: .NET ### Preparation Make sure that you have: * [Installed our .NET library in your project](https://github.com/Adyen/adyen-dotnet-api-library#installation). * [Installed Adyen's root certificate](/point-of-sale/design-your-integration/choose-your-architecture/local#install-root-cert). * [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local#set-up-shared-key). ### Encrypt communications using the .NET library 1. In your C# project, import the required types. ```cs using Adyen; using Adyen.Security; ``` 2. Create an `EncryptionCredentialDetails` object specifying the identifier, passphrase, and version of your shared key. (For instructions, see [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local/#set-up-shared-key).) ```cs var encryptionCredentialDetails = new EncryptionCredentialDetails { KeyVersion = 1, AdyenCryptoVersion = 1, KeyIdentifier = "CryptoKeyIdentifier12345", Password = "p@ssw0rd123456" }; ``` 3. Create a `Config` object specifying the IP address of the terminal (for example, `https://198.51.100.1:8443/nexo`) and the environment: **Test** or **Live**. ```cs var config = new Config { Environment = Model.Environment.Test, LocalTerminalApiEndpoint = @"https://_terminal_:8443/nexo/" // _terminal_ example: `https://198.51.100.1:8443/nexo` (see the Wi-Fi settings of your terminal) }; ``` 4. Initialize a client using the config from the previous step. ```cs var client = new Client(config); ``` 5. Create the `TerminalApiLocalService` using the client from the previous step. ```cs TerminalApiLocalService terminalApiLocalService = new TerminalApiLocalService(client); ``` 6. Make an asynchronous or synchronous call to send a Terminal API request to the payment terminal using the `TerminalApiLocalService`. ```cs // Asynchronous call (preferred) var saleToPOIResponse = await terminalApiLocalService.RequestEncryptedAsync(paymentRequest, encryptionCredentialDetails, new CancellationToken()); // Pass cancellation token or create a new one. // Synchronous (blocking) call //var saleToPOIResponse = terminalApiLocalService.RequestEncrypted(paymentRequest, encryptionCredentialDetails); ``` The library also contains information about how to use local communications without encryption. However, that is only allowed on test while working in parallel on implementing encryption. ### Tab: iOS The Terminal API for iOS library supports deriving the encryption key and encrypting and decrypting communications. ### Preparation Make sure that you have: * [Installed our iOS library](https://github.com/Adyen/adyen-terminal-api-ios#install-terminalapikit) (*TerminalAPIKit*) in your project. * [Installed Adyen's root certificate](/point-of-sale/design-your-integration/choose-your-architecture/local#install-root-cert). * [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local#set-up-shared-key). ### Encrypt communications 1. Derive the key used for encrypting and decrypting local communications between the terminal and your POS app. Make sure to pass the `identifier`, `passphrase`, and `version` of your shared key in string form exactly as they appear in the Customer Area. (For instructions, see [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local/#set-up-shared-key).) ```swift let encryptionKey = try EncryptionKey( identifier: "KEY_IDENTIFIER", passphrase: "KEY_PASSPHRASE", version: KEY_VERSION ) ``` 2. [Create your request](https://github.com/Adyen/adyen-terminal-api-ios#create-terminal-api-requests). For example, create a `Message`. 3. Encrypt your request. ```swift let encryptionKey: EncryptionKey = // the key you derived earlier let request: Message = // the payment request you created let encryptedMessage: Data = try request.encrypt(using: encryptionKey) ``` 4. Send the `encryptedMessage` to the terminal. 5. When you receive the response from the terminal, decrypt the response. ```swift let key: EncryptionKey = // the key you derived earlier let response: Data = // the response you receive from the terminal let encryptedMessage: EncryptedMessage = try Coder.decode(EncryptedMessage.self, from: response) let decryptedMessage: Message = try decrypt(PaymentResponse.self, using: key) ``` ### Tab: Java ### Preparation Make sure that you have: * [Installed our Java library in your project](https://github.com/Adyen/adyen-java-api-library#installation). * [Installed Adyen's root certificate](/point-of-sale/design-your-integration/choose-your-architecture/local#install-root-cert). * [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local#set-up-shared-key). ### Encrypt communications using the Java library 1. Import the required classes. ```java import com.adyen.Client; import com.adyen.Config; import com.adyen.enums.Environment; import com.adyen.httpclient.TerminalLocalAPIHostnameVerifier; import com.adyen.service.TerminalLocalAPI; import com.adyen.model.terminal.security.*; import com.adyen.model.terminal.*; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; import java.security.SecureRandom; ``` 2. Create a keystore for the terminal certificate. ```java KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setCertificateEntry("adyenRootCertificate", adyenRootCertificate); ``` 3. Create a `TrustManagerFactory` that trusts the Certificate Authorities in the keystore. ```java TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); ``` 4. Create an `SSLContext` with the desired protocol that uses our TrustManagers. ```java SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); ``` 5. Configure a client for the `TerminalLocalAPI` service, specifying the IP address of the terminal (for example, `https://198.51.100.1`). ```java Config config = new Config(); config.setEnvironment(environment); config.setTerminalApiLocalEndpoint("https://" + terminalIpAddress); config.setSSLContext(sslContext); config.setHostnameVerifier(new TerminalLocalAPIHostnameVerifier(environment)); Client client = new Client(config); ``` 6. Create a `SecurityKey` object specifying the identifier, passphrase, and version of your shared key. (For instructions, see [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local/#set-up-shared-key).) This object is used to encrypt the payload. ```java SecurityKey securityKey = new SecurityKey(); securityKey.setKeyVersion(1); securityKey.setAdyenCryptoVersion(1); securityKey.setKeyIdentifier("keyIdentifier"); securityKey.setPassphrase("passphrase"); ``` 7. Send a Terminal API request to the payment terminal using the `TerminalLocalAPI` service. ```java TerminalLocalAPI terminalLocalAPI = new TerminalLocalAPI(client, securityKey); TerminalAPIResponse terminalAPIResponse = terminalLocalAPI.request(terminalAPIRequest); ``` The library also contains information about how to use [local communications without encryption](https://github.com/Adyen/adyen-java-api-library?tab=readme-ov-file#using-the-local-terminal-api-integration-without-encryption-only-on-test). However, that is only allowed on test while working in parallel on implementing encryption. ### Tab: Node ### Preparation Make sure that you have: * [Installed our Node library in your project](https://github.com/Adyen/adyen-node-api-library#installation). * [Installed Adyen's root certificate](/point-of-sale/design-your-integration/choose-your-architecture/local#install-root-cert). * [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local#set-up-shared-key). ### Encrypt communications using the Node library 1. In your Node project, require the parts of the module you want to use. ```js const {Client, TerminalLocalAPI} from "@adyen/api-library"; ``` 2. Create a `Config` object with your path to the Adyen root certificate and the IP address of the terminal (for example, `https://198.51.100.1:8443/nexo`), and install and save the certificate in your project folder as `cert.cer`. ```js const config: Config = new Config(); config.certificatePath = "./cert.cer"; config.terminalApiLocalEndpoint = "The IP of your terminal (for example https://198.51.100.1:8443/nexo)"; config.apiKey = "YOUR_ADYEN_API_KEY"; ``` 3. Create a `SecurityKey` object specifying the identifier, passphrase, and version of your shared key. (For instructions, see [Set up a shared key](/point-of-sale/design-your-integration/choose-your-architecture/local/#set-up-shared-key).) ```js const securityKey: SecurityKey = { AdyenCryptoVersion: 1, KeyIdentifier: "keyIdentifier", KeyVersion: 1, Passphrase: "passphrase", }; ``` 4. Initialize the client and the API objects using the config, and create the `TerminalLocalAPI` service. ```js client = new Client({ config }); const terminalLocalAPI = new TerminalLocalAPI(client); ``` 5. Create the request object. ```js const paymentRequest: SaleToPOIRequest = { // The Terminal API `MessageHeader` and `PaymentRequest` } ``` 6. Send the Terminal API request to the payment terminal using the `TerminalLocalAPI` service. ```js const terminalApiResponse: terminal.TerminalApiResponse = await terminalLocalAPI.request(paymentRequest, securityKey); ``` The library also contains information about how to use [local communications without encryption](https://github.com/Adyen/adyen-node-api-library?tab=readme-ov-file#using-the-local-terminal-api-integration-without-encryption-only-on-test). However, that is only allowed on test while working in parallel on implementing encryption. ## Full code samples Select a tab in the code sample block below to see the code for encrypting communications. In all cases you need to know the key identifier, passphrase, and version of your shared key. To find the details of your shared key in your [Customer Area](https://ca-test.adyen.com/): 1. Under **In-person payments**, go to the **Terminal settings** for your merchant account or store. 2. Select **Integrations** and under **Terminal API** go to **Encryption key**. 3. To see the key identifier, passphrase, and version values, select **Decrypted**. **Encryption using a library** #### Java ```java // Import the required classes import com.adyen.Client; import com.adyen.Config; import com.adyen.enums.Environment; import com.adyen.httpclient.TerminalLocalAPIHostnameVerifier; import com.adyen.service.TerminalLocalAPI; import com.adyen.model.terminal.security.*; import com.adyen.model.terminal.*; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; import java.security.SecureRandom; // Create a keystore for the terminal certificate KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); keyStore.setCertificateEntry("adyenRootCertificate", adyenRootCertificate); // Create a TrustManagerFactory that trusts the Certificate Authorities in the keystore TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); // Create an SSLContext with the desired protocol that uses our TrustManagers SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); // Configure a client for the TerminalLocalAPI service // specifying the IP address of the terminal, for example https://198.51.100.1:8443/nexo Config config = new Config(); config.setEnvironment(environment); config.setTerminalApiLocalEndpoint("https://" + terminalIpAddress); config.setSSLContext(sslContext); config.setHostnameVerifier(new TerminalLocalAPIHostnameVerifier(environment)); Client client = new Client(config); // Create a SecurityKey object specifying the identifier, passphrase, and version of your shared key SecurityKey securityKey = new SecurityKey(); securityKey.setKeyVersion(1); securityKey.setAdyenCryptoVersion(1); securityKey.setKeyIdentifier("keyIdentifier"); securityKey.setPassphrase("passphrase"); // Send a Terminal API request to the payment terminal using the TerminalLocalAPI service TerminalLocalAPI terminalLocalAPI = new TerminalLocalAPI(client, securityKey); TerminalAPIResponse terminalAPIResponse = terminalLocalAPI.request(terminalAPIRequest); ``` #### C\# ```cs // In your C# project, import the required types using Adyen; using Adyen.Security; // Create an EncryptionCredentialDetails object specifying the identifier, passphrase, and version of your shared key var encryptionCredentialDetails = new EncryptionCredentialDetails { KeyVersion = 1, AdyenCryptoVersion = 1, KeyIdentifier = "CryptoKeyIdentifier12345", Password = "p@ssw0rd123456" }; // Create a Config object with the IP address of the terminal (for example, https://198.51.100.1:8443/nexo) // and the environment: Test or Live var config = new Config { Environment = Model.Environment.Test, LocalTerminalApiEndpoint = @"https://_terminal_:8443/nexo/" // _terminal_ example: `https://198.51.100.1:8443/nexo` (can be found in the WIFI settings of your terminal) }; // Initialize a client using the config var client = new Client(config); // Create the TerminalApiLocalService using the client TerminalApiLocalService terminalApiLocalService = new TerminalApiLocalService(client); // Make an asynchronous or synchronous call to send a Terminal API request to the payment terminal // Asynchronous call (preferred) var saleToPOIResponse = await terminalApiLocalService.RequestEncryptedAsync(paymentRequest, encryptionCredentialDetails, new CancellationToken()); // Pass cancellation token or create a new one. // Synchronous (blocking) call //var saleToPOIResponse = terminalApiLocalService.RequestEncrypted(paymentRequest, encryptionCredentialDetails); ``` #### NodeJS (JavaScript) ```js // In your Node project, require the parts of the module you want to use const {Client, TerminalLocalAPI} from "@adyen/api-library"; // Create a Config object with your path to the Adyen root certificate and the IP address of the terminal // (for example, `https://198.51.100.1:8443/nexo`), and install and save the certificate in your project folder as `cert.cer`. const config: Config = new Config(); config.certificatePath = "./cert.cer"; config.terminalApiLocalEndpoint = "The IP of your terminal (eg https://192.168.47.169)"; config.apiKey = "YOUR_API_KEY_HERE"; // Create a SecurityKey object specifying the identifier, passphrase, and version of your shared key const securityKey: SecurityKey = { AdyenCryptoVersion: 1, KeyIdentifier: "keyIdentifier", KeyVersion: 1, Passphrase: "passphrase", }; // Initialize the client and the API objects client = new Client({ config }); const terminalLocalAPI = new TerminalLocalAPI(client); // Create the request object const paymentRequest: SaleToPOIRequest = { // The Terminal API `MessageHeader` and `PaymentRequest` } // Send the Terminal API request to the payment terminal const terminalApiResponse: terminal.TerminalApiResponse = await terminalLocalAPI.request(paymentRequest, securityKey); ``` #### Swift ```swift // Derive a key, passing the identifier, passphrase, and version of your shared key in string form let encryptionKey = try EncryptionKey( identifier: "KEY_IDENTIFIER", passphrase: "KEY_PASSPHRASE", version: KEY_VERSION ) // Create your Terminal API request, for example a `Message` // Encrypt the request let encryptionKey: EncryptionKey = // the key you derived earlier let request: Message = // the payment request you created let encryptedMessage: Data = try request.encrypt(using: encryptionKey) // Send the encryptedMessage to the terminal // When you receive the response from the terminal, decrypt the response let key: EncryptionKey = // the key you derived earlier let response: Data = // the response you receive from the terminal let encryptedMessage: EncryptedMessage = try Coder.decode(EncryptedMessage.self, from: response) let decryptedMessage: Message = try decrypt(PaymentResponse.self, using: key) ``` ## Troubleshooting [Crypto errors](#crypto-errors) and [SSL connection errors](#ssl-connection-error) indicate a problem with the protection of the local communications. ### Crypto errors **Example**: ```bash Exception: System.Net.WebException: The remote server returned an error: (401) Unauthorized. ``` The response body contains: ```json { "errors":[ "Nexo Service: crypto error" ], "ServiceID":"1234567890" } ``` **Cause**: Crypto errors are related to the shared key. After you [set up the shared key in your Customer Area](/point-of-sale/design-your-integration/choose-your-architecture/local#set-up-shared-key), the shared key values in your code must match the shared key values in the Customer Area. If you are using a library, check the values for the relevant object: * With the [.NET library](/point-of-sale/design-your-integration/choose-your-architecture/local/protect-with-library?tab=_net_1), check the `EncryptionCredentialDetails` object. * With the [Java library](/point-of-sale/design-your-integration/choose-your-architecture/local/protect-with-library?tab=java_2), check the`SecurityKey` object. * With the [Node library](/point-of-sale/design-your-integration/choose-your-architecture/local/protect-with-library?tab=node_3), check the `SecurityKey` object. If you are using your own code: * Check the [key derivation function](/point-of-sale/design-your-integration/choose-your-architecture/local/protect#derive-key-material). This uses the passphrase of the shared key. * Check the [security trailer function](/point-of-sale/design-your-integration/choose-your-architecture/local/protect#create-the-security-trailer). This uses the version and the identifier of the shared key. ### SSL connection error **Example**: ```bash Exception : System.Net.WebException: The SSL connection could not be established ``` **Possible cause**: Adyen's root certificate is not installed correctly. ## See also * [Building a local integration](/point-of-sale/design-your-integration/choose-your-architecture/local) * [Set up protection of local communications yourself](/point-of-sale/design-your-integration/choose-your-architecture/local/protect)