A secure enterprise chat with React, .NET 10 and Microsoft Foundry
The article targets the common mistake of calling the model straight from the front end with the API key in JavaScript, and instead wires React to a .NET 10 Minimal API that talks to Microsoft Foundry without any keys. It walks through Entra ID authentication, a server-owned system prompt, Server-Sent Events streaming and IP-based rate limiting as the protections that separate a demo from a product.
Key points
- No keys: DefaultAzureCredential and BearerTokenPolicy authenticate against Foundry via Entra ID
- AsIChatClient() adapts the OpenAI client to IChatClient, making provider changes configuration
- The system prompt stays on the server and the DTO only accepts user and assistant roles
- A 20-message window and 4000 characters per message keep cost and latency in check
- .NET 10's TypedResults.ServerSentEvents streams an IAsyncEnumerable without extra libraries
- A fixed-window limiter allows 10 requests per IP per minute, and cancelled requests stop the Foundry call
The post fixes the mistake teams make on their first "company ChatGPT": instead of hiding the key in React code, a .NET 10 Minimal API sits in the middle. It reaches the gpt-5.4-mini deployment in Microsoft Foundry with an Entra ID token, pointing the OpenAI SDK at /openai/v1/ through a BearerTokenPolicy and converting the client with AsIChatClient() into Microsoft.Extensions.AI's IChatClient, so swapping providers becomes configuration.
The system prompt lives only on the server, the request accepts just user and assistant roles, and the last 20 messages with 4000 characters each are the ceiling. Responses stream via TypedResults.ServerSentEvents over an IAsyncEnumerable, request cancellation stops the Foundry call, and a fixed-window limiter allows 10 requests per IP per minute. The React side reads the stream with fetch rather than EventSource.
Real-world use
- An in-product support assistant where the brand voice and system prompt stay server-side while the front end only talks to your API
- A demo environment that works for teammates without Azure access, since an empty endpoint falls back to a simulated chat client
- A SaaS that needs cost control: per-IP rate limits plus a streaming chat that surfaces token usage
- A long-form assistant that stops burning tokens when a user closes the tab mid-answer
Why it matters
This setup closes off leaked keys, prompts editable from DevTools and surprise bills, and the Microsoft.Extensions.AI abstraction means swapping a model or provider no longer requires code changes.