|
| 1 | +--- |
| 2 | +title: Tool Arguments Encryption |
| 3 | +subtitle: Learn to encrypt tool arguments and protect sensitive data |
| 4 | +slug: tools/encryption |
| 5 | +--- |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +Tool argument encryption protects sensitive data like Social Security Numbers, Credit Card Numbers, and other PII by encrypting specific fields before they're sent to your server. |
| 10 | + |
| 11 | +**In this guide, you'll learn to:** |
| 12 | +- Create and configure a custom credential with encryption enabled |
| 13 | +- Generate RSA public/private key pairs |
| 14 | +- Configure tools to encrypt specific argument fields |
| 15 | +- Decrypt encrypted data on your server |
| 16 | + |
| 17 | +## Prerequisites |
| 18 | + |
| 19 | +- A Vapi account with access to the dashboard |
| 20 | +- OpenSSL or a similar tool for generating RSA keys |
| 21 | +- A server endpoint that can receive and decrypt encrypted data |
| 22 | + |
| 23 | +<Steps> |
| 24 | + <Step title="Create a custom credential with encryption"> |
| 25 | + Navigate to the custom credentials page and enable encryption settings. |
| 26 | + |
| 27 | + 1. Go to [https://dashboard.vapi.ai/settings/integrations/custom-credential](https://dashboard.vapi.ai/settings/integrations/custom-credential) and click "Add Custom Credential" |
| 28 | + 2. Check **Enable Encryption** |
| 29 | + 3. Select **RSA-OAEP-256** as the algorithm |
| 30 | + 4. Select **SPKI-PEM** as the format |
| 31 | + |
| 32 | + <Frame caption="Enable encryption in custom credential settings"> |
| 33 | + <img src="../static/images/encryption/custom-credential.png" alt="Custom credential encryption settings" /> |
| 34 | + </Frame> |
| 35 | + </Step> |
| 36 | + |
| 37 | + <Step title="Generate RSA key pair"> |
| 38 | + Use OpenSSL to generate a public/private key pair in PEM format. |
| 39 | + |
| 40 | + Run this command in your terminal to generate both keys: |
| 41 | + |
| 42 | +```bash |
| 43 | +# Generate a 2048-bit RSA private key |
| 44 | +openssl genrsa -out private-key.pem 2048 |
| 45 | + |
| 46 | +# Extract the public key in SPKI format |
| 47 | +openssl rsa -in private-key.pem -pubout -out public-key.pem |
| 48 | +``` |
| 49 | + |
| 50 | + This creates two files: |
| 51 | + - `private-key.pem` - Keep this secure on your server for decryption |
| 52 | + - `public-key.pem` - Copy this to Vapi for encryption |
| 53 | + |
| 54 | + <Warning> |
| 55 | + Never share or commit your private key. Store it securely in your server's environment variables. |
| 56 | + </Warning> |
| 57 | + </Step> |
| 58 | + |
| 59 | + <Step title="Add public key to credential"> |
| 60 | + Copy and paste your public key into the Vapi dashboard. |
| 61 | + |
| 62 | + 1. Open `public-key.pem` and copy the entire contents |
| 63 | + 2. Paste the public key PEM into the **Public Key PEM** field |
| 64 | + 3. Click **Save** |
| 65 | + |
| 66 | + <Frame caption="Paste the public key into the credential"> |
| 67 | + <img src="../static/images/encryption/custom-credential-pem-key.png" alt="Public key PEM field" /> |
| 68 | + </Frame> |
| 69 | + |
| 70 | + Your credential is now ready to use with encrypted tool arguments. |
| 71 | + </Step> |
| 72 | + |
| 73 | + <Step title="Select a tool to configure"> |
| 74 | + Navigate to your tools and choose which tool should use encryption. |
| 75 | + |
| 76 | + 1. Go to the [Tools page](https://dashboard.vapi.ai/tools) |
| 77 | + 2. Select an existing **Custom Tool** or **API Request Tool** |
| 78 | + 3. Alternatively, create a new tool if needed |
| 79 | + </Step> |
| 80 | + |
| 81 | + <Step title="Configure credential and encryption settings"> |
| 82 | + Link your encryption credential and specify which fields to encrypt. |
| 83 | + |
| 84 | + 1. In the tool settings, find the **Credential** dropdown |
| 85 | + 2. Select the credential you created in Step 1 |
| 86 | + 3. Scroll to **Encryption Settings** |
| 87 | + 4. Add the exact JSON paths to the arguments you want encrypted |
| 88 | + |
| 89 | + **Example JSON paths:** |
| 90 | + - `ssn` - Encrypts the `ssn` field |
| 91 | + - `payment.cardNumber` - Encrypts nested fields |
| 92 | + |
| 93 | + <Note> |
| 94 | + JSON paths are relative to the tool's argument structure. Only specified fields will be encrypted. |
| 95 | + </Note> |
| 96 | + |
| 97 | + <Frame caption="Configure credential"> |
| 98 | + <img src="../static/images/encryption/tool-with-credential.png" alt="Tool encryption settings configuration" /> |
| 99 | + </Frame> |
| 100 | + |
| 101 | + <Frame caption="Configure encryption settings"> |
| 102 | + <img src="../static/images/encryption/tool-with-encryption.png" alt="Tool encryption settings configuration" /> |
| 103 | + </Frame> |
| 104 | + </Step> |
| 105 | + |
| 106 | + <Step title="Save and test the configuration"> |
| 107 | + Save your tool configuration and verify encryption works with a test call. |
| 108 | + |
| 109 | + 1. Click **Save** to apply your changes |
| 110 | + 2. Make a test call using an assistant with this tool |
| 111 | + 3. Trigger the tool during the call |
| 112 | + 4. Check your server logs to confirm encrypted data arrives |
| 113 | + |
| 114 | + When your server receives the webhook, encrypted fields will appear as base64-encoded strings: |
| 115 | + |
| 116 | +```json |
| 117 | +{ |
| 118 | + "fullName": "John Doe", |
| 119 | + "dateOfBirth": "ZCT0EvFkJRHShBd06Ldu7ImHgl7YCuX8l8IF/7xuQSydafVWRR2eCGqTeXK7HyMaXyDc3hHyaTwTKyd0kJH0TCgQEJwviTLSlt7IzH4BIVXIadYcmCUbcSN77R6HoYtGE/De8hEYZ0t+bfuKnDY1IyiQXViI1oE+A2hiscrl4x9Or+n3CUSvxXQ3fJREsCHVN4Y4jbLtQOh0bhlsKLol7GEXBGnOG+oBlXvIzEgyco/peusg7Vzeq42F9odQyZZop9u8+ynwz3DOCm9JBZdOuf7iCKKos0NU+VeWanUHvJ2aJfGPck7qleFWDFsCb+F6QcIcn3fkiKTqoYa44vQ+NA==" |
| 120 | +} |
| 121 | +``` |
| 122 | + </Step> |
| 123 | + |
| 124 | + <Step title="Decrypt data on your server"> |
| 125 | + Use your private key to decrypt the base64-encoded encrypted values. |
| 126 | + |
| 127 | + Here's how to decrypt the data in your server code: |
| 128 | + |
| 129 | +<CodeBlocks> |
| 130 | +```typescript title="TypeScript (Node.js)" |
| 131 | +import crypto from 'crypto'; |
| 132 | +import fs from 'fs'; |
| 133 | + |
| 134 | +function decryptToolArgument(encryptedBase64: string): string { |
| 135 | + // Load your private key |
| 136 | + const privateKey = fs.readFileSync('private-key.pem', 'utf8'); |
| 137 | + |
| 138 | + // Decode from base64 |
| 139 | + const encryptedBuffer = Buffer.from(encryptedBase64, 'base64'); |
| 140 | + |
| 141 | + // Decrypt using RSA-OAEP with SHA-256 |
| 142 | + const decrypted = crypto.privateDecrypt( |
| 143 | + { |
| 144 | + key: privateKey, |
| 145 | + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, |
| 146 | + oaepHash: 'sha256', |
| 147 | + }, |
| 148 | + encryptedBuffer |
| 149 | + ); |
| 150 | + |
| 151 | + return decrypted.toString('utf8'); |
| 152 | +} |
| 153 | + |
| 154 | +// Example usage |
| 155 | +const encryptedDateOfBirth = "ZW5jcnlwdGVkX2RhdGFfaGVyZQ==..."; |
| 156 | +const decryptedDateOfBirth = decryptToolArgument(encryptedDateOfBirth); |
| 157 | +console.log(decryptedDateOfBirth); // Original value |
| 158 | +``` |
| 159 | +```python title="Python" |
| 160 | +from cryptography.hazmat.primitives import serialization, hashes |
| 161 | +from cryptography.hazmat.primitives.asymmetric import padding |
| 162 | +from cryptography.hazmat.backends import default_backend |
| 163 | +import base64 |
| 164 | + |
| 165 | +def decrypt_tool_argument(encrypted_base64: str) -> str: |
| 166 | + # Load your private key |
| 167 | + with open('private-key.pem', 'rb') as key_file: |
| 168 | + private_key = serialization.load_pem_private_key( |
| 169 | + key_file.read(), |
| 170 | + password=None, |
| 171 | + backend=default_backend() |
| 172 | + ) |
| 173 | + |
| 174 | + # Decode from base64 |
| 175 | + encrypted_data = base64.b64decode(encrypted_base64) |
| 176 | + |
| 177 | + # Decrypt using RSA-OAEP with SHA-256 |
| 178 | + decrypted = private_key.decrypt( |
| 179 | + encrypted_data, |
| 180 | + padding.OAEP( |
| 181 | + mgf=padding.MGF1(algorithm=hashes.SHA256()), |
| 182 | + algorithm=hashes.SHA256(), |
| 183 | + label=None |
| 184 | + ) |
| 185 | + ) |
| 186 | + |
| 187 | + return decrypted.decode('utf-8') |
| 188 | + |
| 189 | +# Example usage |
| 190 | +encrypted_date_of_birth = "ZW5jcnlwdGVkX2RhdGFfaGVyZQ==..." |
| 191 | +decrypted_date_of_birth = decrypt_tool_argument(encrypted_date_of_birth) |
| 192 | +print(decrypted_date_of_birth) # Original value |
| 193 | +``` |
| 194 | +</CodeBlocks> |
| 195 | + |
| 196 | + <Tip> |
| 197 | + Store your private key in environment variables rather than hardcoding the file path. Use `process.env.PRIVATE_KEY` or `os.getenv("PRIVATE_KEY")`. |
| 198 | + </Tip> |
| 199 | + </Step> |
| 200 | +</Steps> |
| 201 | + |
| 202 | +## Security best practices |
| 203 | + |
| 204 | +Follow these guidelines to maintain secure encryption: |
| 205 | + |
| 206 | +- **Never commit private keys** - Use environment variables or secret management systems |
| 207 | +- **Rotate keys periodically** - Generate new key pairs and update credentials regularly |
| 208 | +- **Encrypt selectively** - Only encrypt fields that contain sensitive data to minimize overhead |
| 209 | +- **Validate decrypted data** - Always validate and sanitize decrypted values before use |
| 210 | +- **Use HTTPS** - Ensure your server endpoint uses HTTPS for transport security |
| 211 | + |
| 212 | +## Next steps |
| 213 | + |
| 214 | +Now that you have tool argument encryption configured: |
| 215 | + |
| 216 | +- **[Custom tools](mdc:fern/tools/custom-tools):** Learn more about creating custom tools |
| 217 | +- **[API request tools](mdc:fern/tools/api-request):** Configure API request tools with encrypted arguments |
| 218 | +- **[Server URLs](mdc:fern/server-url):** Set up secure server endpoints for receiving encrypted data |
0 commit comments