- Run an internal endpoint in your network alongside the service that will receive webhooks
- Create a Cloud Endpoint that verifies each webhook’s signature and forwards it to the internal endpoint
- Confirm that a genuine webhook reaches your service and a forged one is rejected
What you’ll need
- An ngrok account.
- The ngrok agent installed on the machine where your service runs.
- A service running locally that should receive webhooks (this quickstart uses port
8080as an example). - The webhook signing secret for your provider. In GitHub, you’ll set the secret at the repository level: Settings → Webhooks → Secret.
1. Configure an internal endpoint
Open the ngrok configuration file on the machine running your service and add an internal endpoint that points to it. You can do so by editing your config file with thengrok config edit terminal command. Update yours to resemble the following snippet.
ngrok.yml
YOUR_AUTHTOKEN with the authtoken from your ngrok dashboard.
Next, start the agent:
- Using ngrok.yml
- Using a different config file
2. Create a Cloud Endpoint
Cloud Endpoints are persistent, always-on endpoints managed from the dashboard or API. They use an attached Traffic Policy to handle incoming connections. This is where webhook verification and request routing happen. Create a new Cloud Endpoint in the dashboard. Replace the default Traffic Policy with the following:verify-webhook Traffic Policy Action to check the signature on every incoming request and forward only genuine GitHub webhooks to the internal endpoint you configured in step 1. A request that fails verification is rejected with a 403 before it ever reaches your service.
3. Test it
Paste the URL of your ngrok Cloud Endpoint into your GitHub webhook settings at Settings → Webhooks → Payload URL. Make sure that the webhook secret matches the one in your Traffic Policy. Use GitHub’s Recent Deliveries → Redeliver to send a signed event to your Cloud Endpoint. You should receive a verified, signed webhook on your service on port8080.
Make a curl request to confirm that unsigned webhooks are rejected:
403 Forbidden since the request has no valid signature.
What’s next
- Follow the full tutorial for a complete setup with multiple providers, vaulted secrets, and authtoken ACLs.
- Store your signing secrets in a vault instead of pasting them into your policy.
- Verify webhooks from a provider that isn’t on the supported list using a shared-secret check or upstream verification.
- Read how signature verification works and review security best practices.