The network traffic initiated by Dialogflow for webhook requests is sent on a public network. To ensure that traffic is both secure and trusted in both directions, Dialogflow optionally supports Mutual TLS authentication (mTLS). During Dialogflow's standard TLS handshake, your webhook server presents a certificate that can be validated by Dialogflow, either by following the Certificate Authority chain or by comparing the certificate to a Custom CA certificate. By enabling mTLS on your webhook server, Dialogflow will present its Google certificate to your webhook server for validation, completing the establishment of mutual trust.
Requesting mTLS
To request mTLS:
- Prepare your webhook HTTPS server to request the client certificate during the TLS handshake.
- Your webhook server should verify the client certificate upon receiving it.
Install a certificate chain for your webhook server, which can be mutually trusted by both client and server. Applications connecting to Google services should trust all the Certificate Authorities listed by Google Trust Services. You can download root certs from: https://pki.goog/.
Demo Node.js server
The following is a Node.js demo server:
- Prepare a self signed certificate and pem file.
- Prepare the certificate chain file:
curl https://pki.goog/roots.pem >> ca-crt.pem
-
Save the following sample as
server.js
:var https = require('https'); const express = require('express') var fs = require('fs'); var options = { // Specify the key file for the server key: fs.readFileSync('./server-key.pem'), // Specify the certificate file cert: fs.readFileSync('./server-crt.pem'), // Specify the Certificate Authority certificate ca: fs.readFileSync('./ca-crt.pem'), // Requesting the client to provide a certificate, to authenticate the user. requestCert: true, // As specified as "true", so no unauthenticated traffic // will make it to the specified route specified rejectUnauthorized: false }; var app = express(); app.use(function (req, res, next) { if (!req.client.authorized) { //return res.status(401).send('Client cert failed. User is not authorized\n'); } // Examine the cert itself, and even validate based on that! var cert = req.socket.getPeerCertificate(); if (cert.subject) { console.log('Client Certificate: ',cert); console.log('Client Certificate Common Name: '+cert.subject.CN); console.log('Client Certificate Location: '+cert.subject.L); console.log('Client Certificate Organization Name: '+cert.subject.O); console.log('Client Certificate Email Address: '+cert.subject.emailAddress); } res.writeHead(200, {'Content-Type': 'text/plain'}); res.end("hello world from client cert\n"); next(); }); var listener = https.createServer(options, app).listen(4433, function () { console.log('Express HTTPS server listening on port ' + listener.address().port); });
- Run server.js.
-
Set requestCert to be true.
curl https://127.0.0.1:4433 -k
-
Send the client certificate.
SSL handshake successfully completes.
curl -v -s -k --key client-key.pem --cert client-crt.pem https://localhost:4433 openssl s_client -key client-key.pem -cert client-crt.pem -connect localhost:4433 -CAfile ca-crt.pem
Best Practice
To make sure the webhook requests are initiated from your own Dialogflow agents,
you should verify the Bearer service identity token
from the request's Authorization header.
Alternatively, you can verify the project ID in the resource names of the
webhook requests (for example, session
) in your webhook server.
Errors
If client certification fails (for example, no client certificate is sent from the client or the client certificate is not signed correctly), the TLS handshake fails and the session terminates.
Common error messages:
Error message | Explanation |
---|---|
Failed to verify client's certificate: x509: certificate signed by unknown authority | Dialogflow sends its client certificate to the external webhook, but the external webhook cannot verify it. This may be because the external webhook didn't install the CA chain correctly. All root CAs from Google should be trusted. |