-
Notifications
You must be signed in to change notification settings - Fork 156
Add Stripe CLI hosting integration #950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
8697699
Initial plan
Copilot 2076598
Add Stripe CLI hosting integration with tests and example
Copilot a3abaf8
Improve Stripe integration example and documentation
Copilot d4abb78
Fix API project configuration and improve test assertions
Copilot 9af0e44
Fixing tests list
aaronpowell 19d63ff
Getting build to pass
aaronpowell 377e271
Getting the tests passing
aaronpowell 715c5d7
properly resolving the secret for validating requests
aaronpowell b323f21
Adding a new attribute for filtering tests if they require an authent…
aaronpowell e4a85fb
Handling API key and webhook signing token
aaronpowell 8631373
Merge branch 'main' into copilot/add-stripe-cli-integration
aaronpowell 1d5d9e0
Apply suggestions from code review
aaronpowell 4d55c0e
Fix README examples and documentation per code review feedback
Copilot 73bda34
Merge branch 'main' into copilot/add-stripe-cli-integration
aaronpowell 939a731
Fixing build errors
aaronpowell File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
...munityToolkit.Aspire.Hosting.Stripe.Api/CommunityToolkit.Aspire.Hosting.Stripe.Api.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
|
||
| </Project> |
22 changes: 22 additions & 0 deletions
22
examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.Api/Program.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| var builder = WebApplication.CreateBuilder(args); | ||
|
|
||
| var app = builder.Build(); | ||
|
|
||
| app.MapGet("/", () => "Stripe Webhook API"); | ||
|
|
||
| app.MapPost("/payments/stripe-webhook", async (HttpContext context, IConfiguration configuration) => | ||
| { | ||
| var webhookSecret = configuration["STRIPE_WEBHOOK_SECRET"]; | ||
|
|
||
| using var reader = new StreamReader(context.Request.Body); | ||
| var json = await reader.ReadToEndAsync(); | ||
|
|
||
| // In a real application, you would verify the webhook signature here | ||
| // using the STRIPE_WEBHOOK_SECRET | ||
|
|
||
| return Results.Ok(new { received = true, hasSecret = !string.IsNullOrEmpty(webhookSecret) }); | ||
| }); | ||
|
|
||
| app.MapGet("/health", () => Results.Ok()); | ||
|
|
||
| app.Run(); |
26 changes: 26 additions & 0 deletions
26
examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.Api/Properties/launchSettings.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "$schema": "https://json.schemastore.org/launchsettings.json", | ||
| "profiles": { | ||
| "https": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "https://localhost:17227;http://localhost:15019", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development" | ||
| } | ||
| }, | ||
| "http": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "http://localhost:15019", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development" | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
13 changes: 13 additions & 0 deletions
13
...olkit.Aspire.Hosting.Stripe.AppHost/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <Project Sdk="Aspire.AppHost.Sdk/13.0.0"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <UserSecretsId>7e518d7d-87e8-4337-8806-1c99acce5e01</UserSecretsId> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="../CommunityToolkit.Aspire.Hosting.Stripe.Api/CommunityToolkit.Aspire.Hosting.Stripe.Api.csproj" /> | ||
| <ProjectReference Include="../../../src/CommunityToolkit.Aspire.Hosting.Stripe/CommunityToolkit.Aspire.Hosting.Stripe.csproj" IsAspireProjectResource="false" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
15 changes: 15 additions & 0 deletions
15
examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost/Program.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| var api = builder.AddProject<Projects.CommunityToolkit_Aspire_Hosting_Stripe_Api>("api"); | ||
|
|
||
| // Provide a development default; override via configuration in real projects. | ||
| var stripeApiKey = builder.AddParameter("stripe-api-key", secret: true); | ||
|
|
||
| // Forward Stripe webhooks to the API's webhook endpoint | ||
| var stripe = builder.AddStripe("stripe", stripeApiKey) | ||
| .WithListen(api); | ||
|
|
||
| // The API will receive the webhook signing secret via STRIPE_WEBHOOK_SECRET environment variable | ||
| api.WithReference(stripe); | ||
|
|
||
| builder.Build().Run(); |
29 changes: 29 additions & 0 deletions
29
...ples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost/Properties/launchSettings.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| { | ||
| "$schema": "https://json.schemastore.org/launchsettings.json", | ||
| "profiles": { | ||
| "https": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "https://localhost:17217;http://localhost:15269", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development", | ||
| "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:22180", | ||
| "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22179" | ||
| } | ||
| }, | ||
| "http": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "http://localhost:15269", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development", | ||
| "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19031", | ||
| "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20128" | ||
| } | ||
| } | ||
| } | ||
| } |
12 changes: 12 additions & 0 deletions
12
src/CommunityToolkit.Aspire.Hosting.Stripe/CommunityToolkit.Aspire.Hosting.Stripe.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <AdditionalPackageTags>hosting stripe payments webhooks</AdditionalPackageTags> | ||
| <Description>A .NET Aspire integration for the Stripe CLI for local webhook forwarding and testing.</Description> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Aspire.Hosting" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| # CommunityToolkit.Aspire.Hosting.Stripe library | ||
|
|
||
| Provides extension methods and resource definitions for a .NET Aspire AppHost to configure the Stripe CLI for local webhook forwarding and testing. | ||
|
|
||
| ## Getting Started | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| The Stripe CLI must be installed on your machine. You can install it by following the [official Stripe CLI installation guide](https://stripe.com/docs/stripe-cli#install). | ||
|
|
||
| ### Install the package | ||
|
|
||
| In your AppHost project, install the package using the following command: | ||
|
|
||
| ```dotnetcli | ||
| dotnet add package CommunityToolkit.Aspire.Hosting.Stripe | ||
| ``` | ||
|
|
||
| ### Example usage | ||
|
|
||
| Then, in the _Program.cs_ file of your AppHost project, add the Stripe CLI and configure it to forward webhooks to your API: | ||
|
|
||
| ```csharp | ||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| var stripeApiKey = builder.AddParameter("stripe-api-key", "sk_test_default", secret: true); // Override for real keys | ||
|
|
||
| var externalEndpoint = builder.AddExternalService("webhook-endpoint", "http://localhost:5082"); | ||
| var stripe = builder.AddStripe("stripe", stripeApiKey) | ||
| .WithListen(externalEndpoint, webhookPath: "/payments/stripe-webhook"); | ||
|
|
||
| var api = builder.AddProject<Projects.API>("api") | ||
| .WithReference(stripe); | ||
|
|
||
| builder.Build().Run(); | ||
| ``` | ||
|
|
||
| This will: | ||
|
|
||
| 1. Start the Stripe CLI listening for webhook events | ||
| 2. Forward all webhook events to `http://localhost:5082/payments/stripe-webhook` | ||
| 3. Provide the Stripe API key to the container via the `STRIPE_API_KEY` environment variable | ||
| 4. Make the webhook signing secret available to the API project via the `STRIPE_WEBHOOK_SECRET` environment variable | ||
|
|
||
| ### Forwarding to an Aspire endpoint | ||
|
|
||
| You can also construct URLs dynamically using Aspire endpoint references: | ||
|
|
||
| ```csharp | ||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| var api = builder.AddProject<Projects.API>("api") | ||
| .WithHttpEndpoint(port: 5082, name: "http"); | ||
|
|
||
| var stripeApiKey = builder.AddParameter("stripe-api-key", "sk_test_default", secret: true); | ||
|
|
||
| var stripe = builder.AddStripe("stripe", stripeApiKey) | ||
| .WithListen(api, webhookPath: "/payments/stripe-webhook", | ||
| events: ["payment_intent.created", "charge.succeeded"]); | ||
|
|
||
| api.WithReference(stripe); | ||
|
|
||
| builder.Build().Run(); | ||
| ``` | ||
|
|
||
| Note: When constructing URLs with paths, you need to use `ReferenceExpression.Create` to combine the endpoint URL with your webhook path. | ||
|
|
||
| ### Using a custom environment variable for the webhook secret | ||
|
|
||
| By default, the webhook signing secret is exposed as `STRIPE_WEBHOOK_SECRET`. You can customize this: | ||
|
|
||
| ```csharp | ||
| var api = builder.AddProject<Projects.API>("api") | ||
| .WithReference(stripe, webhookSigningSecretEnvVarName: "STRIPE_SECRET"); | ||
| ``` | ||
|
|
||
| ### Configuring API key | ||
|
|
||
| `AddStripe` requires an `IResourceBuilder<ParameterResource>` that supplies your Stripe API key. The value is exposed to the container as the `STRIPE_API_KEY` environment variable. You can optionally reuse the same parameter to add the `--api-key` command-line argument: | ||
|
|
||
| ```csharp | ||
| var apiKey = builder.AddParameter("stripe-api-key", "sk_test_default", secret: true); | ||
|
|
||
| var webhookEndpoint = builder.AddExternalService("webhook-endpoint", "http://localhost:5082"); | ||
| var stripe = builder.AddStripe("stripe", apiKey) | ||
| .WithListen(webhookEndpoint, webhookPath: "/webhooks") | ||
| .WithApiKey(apiKey); // optional: forwards the key to the CLI via --api-key | ||
| ``` | ||
|
|
||
| ### Filtering events | ||
|
|
||
| You can filter which webhook events the Stripe CLI listens for: | ||
|
|
||
| ```csharp | ||
| var stripeApiKey = builder.AddParameter("stripe-api-key", "sk_test_default", secret: true); | ||
| var webhookEndpoint = builder.AddExternalService("webhook-endpoint", "http://localhost:5082"); | ||
| var stripe = builder.AddStripe("stripe", stripeApiKey) | ||
| .WithListen(webhookEndpoint, webhookPath: "/webhooks", | ||
| events: ["payment_intent.created", "charge.succeeded"]); | ||
| ``` | ||
|
|
||
| ## How it works | ||
|
|
||
| The Stripe CLI integration: | ||
|
|
||
| - Runs `stripe listen --forward-to <url>` to listen for webhook events from Stripe's test environment | ||
| - Forwards those events to your local application endpoint | ||
| - Exposes the webhook signing secret so your application can verify webhook authenticity | ||
| - Provides a development-friendly way to test webhook integrations without deploying to production | ||
|
|
||
| ## Additional Information | ||
|
|
||
| For more information about the Stripe CLI: | ||
|
|
||
| - [Stripe CLI Documentation](https://stripe.com/docs/stripe-cli) | ||
| - [Testing webhooks locally](https://stripe.com/docs/webhooks/test) | ||
|
|
||
| https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-stripe | ||
|
|
||
| ## Feedback & contributing | ||
|
|
||
| https://github.com/CommunityToolkit/Aspire | ||
|
|
||
11 changes: 11 additions & 0 deletions
11
src/CommunityToolkit.Aspire.Hosting.Stripe/StripeContainerImageTags.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| namespace CommunityToolkit.Aspire.Hosting.Stripe; | ||
|
|
||
| internal static class StripeContainerImageTags | ||
| { | ||
| /// <summary>docker.io</summary> | ||
| public const string Registry = "docker.io"; | ||
| /// <summary>stripe/stripe-cli</summary> | ||
| public const string Image = "stripe/stripe-cli"; | ||
| /// <summary>v1.33.0</summary> | ||
| public const string Tag = "v1.33.0"; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example uses
WithListenwith a plain string URL, but there is no overload that accepts a string. The available overloads accept eitherIResourceBuilder<IResourceWithEndpoints>orIResourceBuilder<ExternalServiceResource>.To fix this example: