Webhook callback from process automation fails due to SSL ce

Our Mendix 9.24 process automation workflows need to receive webhook callbacks from an external automation platform (UiPath). We’ve configured a REST endpoint in Mendix to receive the callbacks, but the external system consistently fails to deliver them.

UiPath logs show:


SSL handshake failed: unable to get local issuer certificate
Webhook delivery to https://automation.company.com/api/callback failed

Our Mendix app is deployed on a private cloud with a self-signed SSL certificate for internal testing. The certificate works fine for browser access (after accepting the warning), but webhook systems can’t bypass the certificate validation. We need webhooks working for our process automation to function correctly. What’s the proper approach to handle SSL certificate trust for webhook callbacks in Mendix?

Self-signed certificates are the root cause. Webhook systems (correctly) refuse to connect to endpoints without valid SSL certificates from trusted CAs. For production, you need a proper certificate from Let’s Encrypt or a commercial CA. For testing environments, you have two options: use a trusted certificate anyway, or configure the external system to trust your self-signed cert.

Getting a proper certificate for our test environment takes weeks due to corporate security approval processes. Is there a way to configure Mendix to accept webhook callbacks without SSL, or can we add our self-signed certificate to UiPath’s trust store temporarily?

Another consideration - even with valid SSL, you need to verify that your Mendix REST endpoint is configured to handle the specific webhook format UiPath sends. Check the request headers, authentication method, and payload structure. UiPath typically sends JSON with specific fields like eventType, timestamp, and data. Your endpoint needs to parse these correctly.

Here’s a comprehensive solution covering SSL certificate trust, webhook callback troubleshooting, and REST endpoint security:

1. SSL Certificate Trust Solutions:

Option A - Proper Certificate (Recommended for Production):

For production and staging environments, use a certificate from a trusted CA:

# Using Let's Encrypt (free, automated)
certbot certonly --standalone -d automation.company.com

# Configure Mendix Cloud to use the certificate
# Or for on-premises: Update Java keystore
keytool -import -alias automation-cert -file cert.pem \
  -keystore $JAVA_HOME/lib/security/cacerts

Option B - Development Tunnel (Testing Only):

For development/testing with self-signed certs:

# Using ngrok
ngrok http https://localhost:8080
# Provides: https://abc123.ngrok.io -> your local Mendix

# Update UiPath webhook URL to ngrok URL
# Ngrok provides valid SSL automatically

Option C - Trust Self-Signed Certificate (UiPath Side):

If you control both systems, add your cert to UiPath’s trust store:

# Export your Mendix certificate
openssl s_client -connect automation.company.com:443 -showcerts > mendix-cert.pem

# Import to UiPath server trust store
Import-Certificate -FilePath mendix-cert.pem \
  -CertStoreLocation Cert:\LocalMachine\Root

2. Webhook Callback Troubleshooting:

Create comprehensive webhook endpoint with logging:

// WebhookHandler.java
public String handleWebhook(IContext context, String requestBody,
                           IMendixObject requestHeaders) {
    try {
        // Log incoming webhook for debugging
        logger.info("Webhook received: " + requestBody);
        logger.info("Headers: " + getHeadersString(requestHeaders));

        // Verify SSL client certificate (if mutual TLS)
        if (!verifyClientCertificate(context)) {
            return createErrorResponse(401, "Invalid client certificate");
        }

        // Parse webhook payload
        JSONObject payload = new JSONObject(requestBody);
        processWebhook(context, payload);

        return createSuccessResponse();
    } catch (Exception e) {
        logger.error("Webhook processing failed: " + e.getMessage());
        return createErrorResponse(500, e.getMessage());
    }
}

3. REST Endpoint Security Implementation:

Signature Verification (Critical):

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public boolean verifyWebhookSignature(String payload, String signature, String secret) {
    try {
        Mac hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
        hmac.init(secretKey);

        byte[] hash = hmac.doFinal(payload.getBytes());
        String computed = Base64.getEncoder().encodeToString(hash);

        return computed.equals(signature);
    } catch (Exception e) {
        logger.error("Signature verification failed: " + e.getMessage());
        return false;
    }
}

In your REST endpoint microflow:


// Extract signature from header
signature = $RequestHeaders/X-UiPath-Signature

// Verify before processing
if (!verifyWebhookSignature($RequestBody, signature, $WebhookSecret)) {
    return { "status": 401, "message": "Invalid signature" };
}

// Process webhook only if signature is valid
processAutomationCallback($RequestBody);

4. Complete Webhook Endpoint Configuration:

REST Service Definition:


POST /api/automation/webhook
Authentication: Custom (signature-based)
Content-Type: application/json

Required Headers:
- X-UiPath-Signature: HMAC-SHA256 signature
- X-UiPath-Event: Event type (process.completed, process.failed)
- X-UiPath-Timestamp: Unix timestamp (for replay protection)

Replay Attack Prevention:

public boolean isReplayAttack(long timestamp) {
    long currentTime = System.currentTimeMillis() / 1000;
    long maxAge = 300; // 5 minutes

    return Math.abs(currentTime - timestamp) > maxAge;
}

5. SSL Certificate Chain Validation:

For custom certificate validation in Mendix:

import javax.net.ssl.*;
import java.security.cert.X509Certificate;

public void configureSSLContext() throws Exception {
    TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {}
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // Add custom validation logic here
                validateCertificateChain(certs);
            }
        }
    };

    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}

Note: Only use custom trust managers for specific integration scenarios. Default validation is preferred.

6. Webhook Delivery Monitoring:

Implement health check endpoint:


GET /api/automation/webhook/health
Response: {"status": "healthy", "lastWebhook": "2025-01-28T14:30:00Z"}

// Microflow checks:
- SSL certificate expiration
- Last successful webhook timestamp
- Endpoint accessibility from external IP

7. UiPath Configuration:

Configure webhook in UiPath Orchestrator:

{
  "url": "https://automation.company.com/api/automation/webhook",
  "secret": "your-shared-secret-key",
  "events": ["process.completed", "process.failed"],
  "headers": {
    "X-API-Key": "additional-auth-if-needed"
  },
  "retryPolicy": {
    "maxRetries": 3,
    "retryDelay": 5000
  }
}

8. Testing Webhook Endpoint:

Create test script to simulate UiPath webhook:

#!/bin/bash
PAYLOAD='{"eventType":"process.completed","processId":"12345"}'
TIMESTAMP=$(date +%s)
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "secret" -binary | base64)

curl -X POST https://automation.company.com/api/automation/webhook \
  -H "Content-Type: application/json" \
  -H "X-UiPath-Signature: $SIGNATURE" \
  -H "X-UiPath-Timestamp: $TIMESTAMP" \
  -d "$PAYLOAD"

9. Error Handling and Logging:

public void processWebhook(IContext context, JSONObject payload) {
    String processId = payload.getString("processId");
    String eventType = payload.getString("eventType");

    try {
        // Retrieve corresponding process instance
        IMendixObject process = retrieveProcess(context, processId);

        if (process == null) {
            logger.warn("Process not found: " + processId);
            // Store failed webhook for manual review
            storeFailedWebhook(context, payload);
            return;
        }

        // Update process status based on event
        updateProcessStatus(context, process, eventType);

        logger.info("Webhook processed successfully: " + processId);
    } catch (Exception e) {
        logger.error("Webhook processing error: " + e.getMessage());
        // Implement retry logic or dead letter queue
        queueForRetry(context, payload);
    }
}

10. Production Checklist:

  • ✓ Valid SSL certificate from trusted CA
  • ✓ HMAC signature verification enabled
  • ✓ Replay attack prevention (timestamp validation)
  • ✓ IP whitelist for webhook source (if possible)
  • ✓ Rate limiting to prevent abuse
  • ✓ Comprehensive logging for audit trail
  • ✓ Alert on webhook delivery failures
  • ✓ Regular certificate renewal monitoring

Security Best Practices:

  1. Never disable SSL validation in production
  2. Rotate webhook secrets every 90 days
  3. Use separate secrets for dev/staging/production
  4. Monitor for unusual webhook patterns
  5. Implement request size limits (prevent DoS)
  6. Log all webhook attempts (successful and failed)

This comprehensive approach ensures secure, reliable webhook delivery from external automation platforms to your Mendix process automation workflows while maintaining proper SSL certificate trust and REST endpoint security.