Skip to content

DevTunnels Webhook Example

Demonstrates Aspire 13's DevTunnels feature for exposing local services to the public internet, enabling webhook development and testing.

📋 Overview

This example shows how to:

  • Expose local APIs to the internet using Azure DevTunnels
  • Receive webhooks from external services during local development
  • Support both public (anonymous) and private (authenticated) tunnel access
  • View webhooks in real-time with a React dashboard

🏗️ Architecture

flowchart TB
    External["External Webhook Provider<br/>(Any Service)"] --> DevTunnel

    subgraph DevTunnel["DevTunnel (Azure)"]
        Public["Public: https://xxx-23001...<br/>Anonymous access for webhooks"]
        Private["Private: https://xxx-23002...<br/>Authenticated access for testing"]
    end

    DevTunnel --> API

    subgraph API["WebhookReceiver.Api"]
        PublicEndpoint["public endpoint :23001<br/>Receives webhooks"]
        InternalEndpoint["internal endpoint :23002<br/>Admin/dashboard access"]
    end

    API --> Dashboard["WebhookReceiver.Dashboard<br/>(React/Vite/TypeScript)<br/>View webhooks in real-time"]

🧩 Components

Project Description
WebhookReceiver.Api .NET Minimal API with named Kestrel endpoints (public/internal)
WebhookReceiver.Dashboard React/Vite/TypeScript app for viewing webhooks
WebhookReceiver.AppHost Aspire orchestration with DevTunnel configuration

🔑 Key Features

  • Named Endpoints: API exposes public (23001) and internal (23002) endpoints via Kestrel
  • Dual Tunnel Access: Public endpoint is anonymous, internal endpoint requires authentication
  • Persistent Tunnel ID: Uses named tunnel for consistent identification and token generation
  • Token Authentication: Supports DevTunnel tokens for secure access to private endpoint
  • Service Discovery: Dashboard receives tunnel URL via Aspire's service discovery
  • Custom Commands: "Delete Tunnel" command in Aspire dashboard to reset the tunnel

📂 Project Structure

foundry/dotnet/devtunnels-simple-webhook/
├── WebhookReceiver.sln
├── webhook.http                      # Test requests
├── WebhookReceiver.AppHost/
│   └── Program.cs                    # Aspire with DevTunnel config
├── WebhookReceiver.Api/
│   └── Program.cs                    # Webhook endpoints
└── WebhookReceiver.Dashboard/        # React frontend
    ├── src/
    └── package.json

🚀 Getting Started

Prerequisites

  • .NET 10.0 SDK
  • Node.js 22.x or 24.x and npm
  • DevTunnel CLI (authenticated with devtunnel user login)

Running the Example

  1. Install Dashboard dependencies:
cd foundry/dotnet/devtunnels-simple-webhook/WebhookReceiver.Dashboard
npm install
cd ..
  1. Start with Aspire:
dotnet run --project WebhookReceiver.AppHost
  1. Get Tunnel URLs from the Aspire Dashboard

📡 API Endpoints

Endpoint Method Description
/api/webhooks POST Receive a webhook
/api/webhooks GET List all webhooks
/api/webhooks/{id} GET Get webhook by ID
/api/webhooks DELETE Clear all webhooks
/api/webhooks/count GET Get webhook count
/health GET Health check

💡 Use Cases

  • Third-Party Integrations: Test Stripe, GitHub, or other webhook integrations locally
  • Development Workflows: Share local APIs with teammates for testing
  • Demo Environments: Expose local services for demonstrations

📍 Source Code

Location: foundry/dotnet/devtunnels-simple-webhook/