HTTP/3 with ASP.NET Core and browsers06/06/2026 | 4 minutes to read
Configure ASP.NET Core WebApi
In this post I explore how to test locally an ASP.NET Core WebApi with HTTP/3 in a local environment using a browser. In ASP.NET Core with .NET 10, HTTP/3 is already supported, but it is an opt-in feature.
To enable HTTP/3, add the following configuration to the application, either in the appsettings.json file
"Kestrel": { "EndpointDefaults": { "Protocols": "Http1AndHttp2AndHttp3" } }
or by environment variables: ASPNETCORE_Kestrel__EndpointDefaults__Protocols=Http1AndHttp2AndHttp3 or by code.
On a local environment, the application is hosted on localhost:port, something similar to this in the launchSettings.json:
In the following examples, I use port 7297. Substitute this with the port used by your application.
"https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, "launchUrl": "weatherforecast", "applicationUrl": "https://localhost:7297;http://localhost:5177", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_Kestrel__EndpointDefaults__Protocols": "Http1AndHttp2AndHttp3" // 👈 HTTP/3 enabled as env var. }
The Kestrel webserver will add a response header: alt-svc: h3=":7297"; ma=86400 advertising the HTTP/3 service endpoint. The very first request is always HTTP/1.1 or HTTP/2. Future requests may use HTTP/3 for the initial request too, if 0-RTT is supported by the client and the server.
The localhost (127.0.0.1) means that msquic will listen to all IP addresses (0.0.0.0), but internally filters incoming requests' IP address to 127.0.0.1. See this reference for further details.
In certain clients this means that using the https://localhost:7297 address might return an ALPN error:
Request Error System.Net.Http.HttpRequestException: Application layer protocol negotiation error was encountered. (localhost:7297)
---> System.Security.Authentication.AuthenticationException: Application layer protocol negotiation error was encountered.
at System.Net.Quic.QuicConnection.
In such cases, try accessing the API as https://127.0.0.1:7297.
Note that only the https address will work, as QUIC requires TLS encryption. By default an ASP.NET Core application in the dev environment will set up self-signed certificates. On Windows these are stored under Current User/My as well as the Trusted Roots. Browsers can use the certificates from this store. Here, the latest .NET 10 certificates are required, as those include both the DNS Name=localhost and the IP Address=127.0.0.1 in the Subject Alternative Name field.
Most browsers won't support requesting the endpoint on HTTP/3 with a self-signed certificate out of the box. For that, some of the settings must be tweaked.
Chrome / Chromium / Edge
The following Chromium documentation explains how to configure Chrome. TLDR:
- Export the dev certificate (public part) from the certificate store and convert it to PEM format.
- Use openssl to generate the SPKI using the following commands:
openssl x509 -noout -pubkey -in aspnetdevcert.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64 - Start the browser (here chromium based msedge) by passing output from the previous command on an ignore list argument:
msedge --user-data-dir=/tmp/chrome-profile --origin-to-force-quic-on=127.0.0.1:7297 --ignore-certificate-errors-spki-list='5tq...' https://127.0.0.1:7297 - The browser will show a warning and open the page using HTTP/3 (remember, after refresh only with 1-RTT).
Firefox
- Open Firefox and in about:config update network.http.http3.disable_when_third_party_roots_found setting to
falseand network.http.http3.force-use-alt-svc-mapping-for-testing totrue. - Restart the browser and open the webapi endpoint.
- Refresh after the initial request (remember alt-svc, 1-RTT).
For further reference, see the following documentation.
CHttp
CHttp is a curl like tool that uses HttpClient (and msquic) under the hood to send HTTP/3 requests. Run the following command to load the endpoint:
.\chttp.exe --uri https://localhost:7297 --method GET -v 3
If the dev certificates are not installed locally, add the --no-certificate-validation flag to suppress cert errors.