Create a workflow
Workflows
You can generate unique encryption keys to be used to make secure API calls within your workflows.
Encryption keys protect sensitive data and should be updated regularly for continued protection.
Keys are per-workflow, so you can have different keys for different workflows. You can also have multiple keys for a single workflow, but only one key can be active at a time.
When a POST request is made using the kinde.secureFetch binding, the body is automatically encrypted with the active encryption key for the workflow.
Kinde uses AES-256-GCM encryption for secure data transfer. The entire request body is sent as a Base64URL-encoded string. Use the same encryption key in your own code to decrypt the payload on arrival. This ensures secure transfer of the data.
Decrypting methods depend on your systems and framework. Here’s how to decrypt if you are using .NET.
Situation: You use kinde.secureFetch and the payload is encrypted with your workflow’s active encryption key using AES-GCM, then encoded in Base64.
Method: Decrypt the request body in your .NET API:
System.Security.Cryptography.AesGcm class for decryption.The payload structure includes the nonce (IV), tag, and ciphertext. These will be provided in the encrypted request payload, so your code should parse them out before decrypting.
using System;using System.Security.Cryptography;using System.Text;using System.Text.Json;
public class WorkflowPayloadDecryptor{ private readonly byte[] _encryptionKey;
public WorkflowPayloadDecryptor(string base64EncryptionKey) { _encryptionKey = Convert.FromBase64String(base64EncryptionKey); }
public string DecryptPayload(string encryptedPayload) { try { // Step 1: Base64 decode the incoming payload byte[] encryptedData = Convert.FromBase64String(encryptedPayload);
// Step 2: Parse the payload structure // The payload contains: nonce (12 bytes) + tag (16 bytes) + ciphertext const int nonceLength = 12; const int tagLength = 16;
if (encryptedData.Length < nonceLength + tagLength) { throw new ArgumentException("Invalid encrypted payload structure"); }
// Extract components byte[] nonce = new byte[nonceLength]; byte[] tag = new byte[tagLength]; byte[] ciphertext = new byte[encryptedData.Length - nonceLength - tagLength];
Array.Copy(encryptedData, 0, nonce, 0, nonceLength); Array.Copy(encryptedData, nonceLength, tag, 0, tagLength); Array.Copy(encryptedData, nonceLength + tagLength, ciphertext, 0, ciphertext.Length);
// Step 3: Decrypt using AES-GCM using (var aesGcm = new AesGcm(_encryptionKey)) { byte[] decryptedBytes = new byte[ciphertext.Length]; aesGcm.Decrypt(nonce, ciphertext, tag, decryptedBytes);
// Convert decrypted bytes to string return Encoding.UTF8.GetString(decryptedBytes); } } catch (Exception ex) { throw new InvalidOperationException("Failed to decrypt workflow payload", ex); } }}
// Example usage in an ASP.NET Core controller[ApiController][Route("api/[controller]")]public class WorkflowController : ControllerBase{ private readonly WorkflowPayloadDecryptor _decryptor;
public WorkflowController(IConfiguration configuration) { // Get the encryption key from configuration string encryptionKey = configuration["KindeWorkflowEncryptionKey"]; _decryptor = new WorkflowPayloadDecryptor(encryptionKey); }
[HttpPost("webhook")] public async Task<IActionResult> HandleWorkflowWebhook() { try { // Read the encrypted payload from the request body using var reader = new StreamReader(Request.Body); string encryptedPayload = await reader.ReadToEndAsync();
// Decrypt the payload string decryptedJson = _decryptor.DecryptPayload(encryptedPayload);
// Parse the decrypted JSON var workflowData = JsonSerializer.Deserialize<WorkflowData>(decryptedJson);
// Process the decrypted data // ... your business logic here ...
return Ok(new { message = "Workflow payload processed successfully" }); } catch (Exception ex) { return BadRequest(new { error = "Failed to process workflow payload", details = ex.Message }); } }}
// Example data model for the decrypted payloadpublic class WorkflowData{ public string UserId { get; set; } public string EventType { get; set; } public Dictionary<string, object> Data { get; set; }}Add your workflow encryption key to your appsettings.json:
{ "KindeWorkflowEncryptionKey": "your-base64-encoded-encryption-key-here"}Or set it as an environment variable:
KindeWorkflowEncryptionKey=your-base64-encoded-encryption-key-hereYou can change the active status of any key. Remember to update your code to use the active key.
Deleting used keys is good security hygiene. But deleting an active key can also break your code. Only delete inactive keys.