If you have spent any time building C# applications that make HTTPS calls, you have probably run into this headache: AuthenticationException: The remote certificate is invalid according to the validation procedure. It pops up during local development, in Docker containers, and sometimes in production without warning. I have dealt with this error across dozens of .NET projects, and I can tell you that the fix depends entirely on why the validation is failing.
In this guide, you will learn how to fix “The Remote Certificate Is Invalid” error in C# using multiple approaches. We will cover quick development bypasses, proper certificate trust setup, IHttpClientFactory patterns, and platform-specific solutions for Docker and Linux. I will also show you how to diagnose exactly which certificate error you are hitting so you apply the right fix instead of guessing.
By the end, you will have a complete toolkit for resolving SSL/TLS certificate validation errors in any .NET environment, whether you are debugging on localhost with Kestrel or deploying to a Linux Docker container.
Table of Contents
What Causes the Remote Certificate Is Invalid Error?
The “remote certificate is invalid” error in C# occurs when the .NET runtime cannot verify the SSL/TLS certificate presented by a remote server during an HTTPS connection. The HttpClient class validates every server certificate against the operating system’s trusted root certificate store. When that validation fails, .NET throws an AuthenticationException and blocks the connection entirely.
This is actually a good thing. Certificate validation protects you from man-in-the-middle attacks by ensuring you are connecting to the real server, not an impostor. The problem is that legitimate certificates can fail validation for several reasons, especially in development environments.
The full error message usually includes a specific reason. Here are the four most common variations you will encounter:
- UntrustedRoot – The certificate chain ends at a root certificate that is not in your system’s trust store. This happens constantly with self-signed certificates and the ASP.NET Core development certificate.
- PartialChain – The server did not send all intermediate certificates needed to build a complete chain to a trusted root. This is common when consuming third-party APIs that are misconfigured.
- NotTimeValid (also shown as NotValidTime) – The certificate has expired or is not yet valid. The ASP.NET Core dev certificate expires after one year, which catches developers off guard.
- HostnameMismatch (RemoteCertificateNameMismatch) – The hostname in the URL does not match the hostname on the certificate. This happens when you connect to an IP address instead of a domain name.
Understanding which specific error you are seeing is the first step to fixing it. The error message in your exception usually tells you exactly what went wrong, but you need to read it carefully.
How to Diagnose Your Specific Certificate Error
Before applying any fix, I recommend adding a diagnostic callback to identify the exact reason your certificate validation is failing. This saves you from trying solution after solution blindly. Here is a diagnostic snippet you can drop into your code temporarily:
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
Console.WriteLine($"SSL Policy Errors: {sslPolicyErrors}");
Console.WriteLine($"Certificate Subject: {cert?.Subject}");
Console.WriteLine($"Certificate Issuer: {cert?.Issuer}");
Console.WriteLine($"Valid From: {cert?.NotBefore}");
Console.WriteLine($"Valid Until: {cert?.NotAfter}");
if (chain != null)
{
foreach (var status in chain.ChainStatus)
{
Console.WriteLine($"Chain Status: {status.Status} - {status.StatusInformation}");
}
}
return false; // Still fail so you can read the output
};
var client = new HttpClient(handler);
try
{
var response = await client.GetAsync("https://localhost:5001/api/test");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
This callback intercepts the validation process and prints the exact SslPolicyErrors value and chain status information before rejecting the connection. The output tells you precisely what is wrong:
Nonewith chain errors means a partial chain problemRemoteCertificateChainErrorsusually means UntrustedRoot or PartialChainRemoteCertificateNameMismatchmeans the hostname does not matchRemoteCertificateNotAvailablemeans no certificate was provided at all
Once you know the specific error, you can apply the targeted fix from the sections below.
Quick Fix: How to Bypass Certificate Validation in Development
Sometimes you just need to get unblocked during local development. Bypassing certificate validation is the fastest way to do that, but it comes with a serious security trade-off. I want to be very clear about this: never bypass certificate validation in production. Doing so makes your application vulnerable to man-in-the-middle attacks where attackers can intercept and read all your HTTPS traffic.
That said, for local development against localhost, here are the two most common bypass methods.
Method 1: HttpClientHandler with DangerousAcceptAnyServerCertificateValidator
The simplest bypass uses the built-in DangerousAcceptAnyServerCertificateValidator property. This is available in .NET Core 2.1 and later, including .NET 5, 6, 7, 8, and 9:
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
var client = new HttpClient(handler);
var response = await client.GetAsync("https://localhost:5001/api/data");
The name DangerousAcceptAnyServerCertificateValidator is intentionally scary. Microsoft named it that way to discourage casual use. It accepts any certificate regardless of validity, which is fine for localhost testing but dangerous everywhere else.
Method 2: Custom ServerCertificateCustomValidationCallback
For more control, you can write a custom callback that always returns true. This approach lets you add conditions later, such as only bypassing for specific hosts:
var handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
// WARNING: This bypasses ALL certificate validation.
// Only use in development. Never use in production.
return true;
};
var client = new HttpClient(handler);
You can also restrict the bypass to localhost only, which is safer:
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
if (sender is HttpRequestMessage request &&
request.RequestUri?.Host == "localhost")
{
return true;
}
return sslPolicyErrors == SslPolicyErrors.None;
};
This conditional approach lets you bypass validation for local development while maintaining full validation for external API calls. It is a pattern I use frequently in development configurations.
Method 3: Bypass for gRPC and Other Channels
If you are working with gRPC in C#, the approach is slightly different. You configure the channel handler directly:
var handler = new SocketsHttpHandler
{
SslOptions = new SslClientAuthenticationOptions
{
RemoteCertificateValidationCallback = (sender, cert, chain, errors) => true
}
};
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
HttpHandler = handler
});
The SocketsHttpHandler is the default handler in modern .NET and provides the same callback mechanism through SslOptions.
Proper Fix: Correcting Certificate Trust the Right Way
Bypassing validation works for quick fixes, but the proper approach is to fix the underlying trust issue. This means either trusting the certificate in your operating system’s certificate store or regenerating a valid development certificate. I recommend this approach for any project that will be worked on by a team.
Fix 1: Regenerate and Trust the ASP.NET Core Development Certificate
The most common cause of this error in local development is an expired or corrupted ASP.NET Core HTTPS development certificate. The dev certificate expires after one year, and Visual Studio sometimes caches an old, invalid version. Here is how to fix it with dotnet dev-certs:
// Step 1: Clean existing dev certificates
dotnet dev-certs https --clean
// Step 2: Generate a new development certificate
dotnet dev-certs https
// Step 3: Trust the new certificate (Windows/macOS)
dotnet dev-certs https --trust
On Windows, this adds the certificate to the Trusted Root Certification Authorities store. On macOS, it adds the certificate to the system keychain. After running these commands, restart your application and the certificate error should disappear.
If dotnet dev-certs https --trust does not seem to work, try these additional steps:
- Close all instances of Visual Studio and your browser
- Delete the
%APPDATA%\ASP.NET\Httpsfolder on Windows (or~/.aspnet/httpson macOS/Linux) - Open Windows Internet Options, go to Content > Certificates, and remove any old ASP.NET Core certificates from the Trusted Root store
- Run the three
dotnet dev-certscommands above again - Clear your browser’s cache and local storage, especially if you are using Chrome
I have seen cases where Chrome’s Local Storage cached the invalid certificate state even after the certificate was fixed. Clearing the browser data resolved it immediately.
Fix 2: Trust a Self-Signed Certificate on Windows
If you are connecting to a service with a self-signed certificate, you need to add that certificate to your Windows trust store manually. First, export the certificate from the server, then import it:
// Using PowerShell to import a certificate to the trusted root store
$certPath = "C:\path\to\certificate.cer"
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath)
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("Root", "LocalMachine")
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()
Write-Host "Certificate added to Trusted Root store"
Alternatively, you can double-click the .cer file and use the Certificate Import Wizard to place it in the Trusted Root Certification Authorities store. Either approach achieves the same result.
Fix 3: Trust a Self-Signed Certificate on Linux
On Linux, the process is different. You copy the certificate (in PEM format) to the system certificate directory and run the update command. The exact commands depend on your distribution:
# Ubuntu/Debian
sudo cp mycert.crt /usr/local/share/ca-certificates/mycert.crt
sudo update-ca-certificates
# RHEL/CentOS/Fedora
sudo cp mycert.pem /etc/pki/ca-trust/source/anchors/mycert.pem
sudo update-ca-trust
After running the update command, .NET applications on that system will trust the certificate. This is important for Linux-based Docker containers, which we will cover in the next section.
Using IHttpClientFactory for Certificate Configuration
In modern ASP.NET Core applications, you should not be creating HttpClient instances directly. Instead, use IHttpClientFactory with dependency injection. This avoids socket exhaustion issues and gives you a centralized place to configure certificate validation.
Here is how to configure certificate validation bypass through IHttpClientFactory in your Program.cs or Startup.cs:
builder.Services.AddHttpClient("DevClient", client =>
{
client.BaseAddress = new Uri("https://localhost:5001/");
})
.ConfigurePrimaryHttpMessageHandler(() =>
{
return new SocketsHttpHandler
{
ServerCertificateCustomValidationCallback = (sender, cert, chain, errors) => true
};
});
You then inject the named client wherever you need it:
public class MyService
{
private readonly HttpClient _client;
public MyService(IHttpClientFactory factory)
{
_client = factory.CreateClient("DevClient");
}
public async Task GetDataAsync()
{
var response = await _client.GetAsync("api/data");
return await response.Content.ReadAsStringAsync();
}
}
Environment-Based Validation Strategy
The best practice is to bypass validation only in development and enforce it in production. You can do this with environment checks:
builder.Services.AddHttpClient("ApiClient", client =>
{
client.BaseAddress = new Uri(builder.Configuration["ApiBaseUrl"]);
})
.ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new SocketsHttpHandler();
if (builder.Environment.IsDevelopment())
{
handler.ServerCertificateCustomValidationCallback =
(sender, cert, chain, errors) => true;
}
return handler;
});
This pattern ensures that certificate validation is always enforced in production while making local development painless. I recommend this approach for any team project because it prevents accidental security holes from being deployed.
Using Typed Clients for Better Organization
For larger projects, typed clients provide better encapsulation. You define a dedicated client class and register it with the factory:
public class ExternalApiClient
{
private readonly HttpClient _client;
public ExternalApiClient(HttpClient client, IHostEnvironment env)
{
_client = client;
// Environment-specific logic can go here
}
public async Task GetAsync(string endpoint)
{
var response = await _client.GetAsync(endpoint);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync();
}
}
// Registration in Program.cs
builder.Services.AddHttpClient(client =>
{
client.BaseAddress = new Uri("https://api.example.com/");
});
Typed clients make your code more testable and keep certificate configuration centralized in your DI setup.
Platform-Specific Solutions (Docker, Linux, IIS)
Certificate validation behavior varies significantly across platforms. The same code that works on Windows might fail on Linux or in a Docker container. Here is how to handle the most common platform-specific scenarios.
Docker Container Certificate Trust
Docker containers start with a minimal certificate store that does not include your development certificates. If your .NET app runs in Docker and needs to call an HTTPS endpoint with a self-signed certificate, you need to add the certificate to the container’s trust store. Here is a Dockerfile approach:
FROM mcr.microsoft.com/dotnet/aspnet:8.0
# Copy your certificate into the container
COPY mycert.crt /usr/local/share/ca-certificates/mycert.crt
# Update the certificate store (Debian/Ubuntu base images)
RUN apt-get update && apt-get install -y ca-certificates
RUN update-ca-certificates
# Rest of your Dockerfile
COPY . /app
WORKDIR /app
ENTRYPOINT ["dotnet", "MyApp.dll"]
For development scenarios where you want to trust the ASP.NET Core dev certificate inside Docker, the simplest approach is to use the dev certificate bypass in your Docker Compose development override file:
// docker-compose.override.yml environment variable
environment:
- ASPNETCORE_ENVIRONMENT=Development
- DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=1
// In your Program.cs, check for the Docker environment
if (builder.Environment.IsDevelopment())
{
builder.Services.AddHttpClient("Api")
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
});
}
I have also found that simply restarting the Docker daemon can resolve certificate chain issues. Docker sometimes caches a stale certificate state that a restart clears immediately.
Linux Development Certificate Setup
If you develop on Linux directly (not in Docker), the dotnet dev-certs https --trust command requires additional setup. On Ubuntu, you need to install libglib2.0-0 and ca-certificates first. On other distributions, you may need to manually export and trust the certificate:
# Generate the dev certificate
dotnet dev-certs https
# Export it to PEM format
dotnet dev-certs https -ep ~/.dotnet/corefx/cryptography/x509stores/my/certificate.pem --format Pem
# Trust it at the system level
sudo cp ~/.dotnet/corefx/cryptography/x509stores/my/certificate.pem /usr/local/share/ca-certificates/dotnet-dev.crt
sudo update-ca-certificates
The exact path for the certificate store may vary. Check the .NET documentation for your specific distribution.
IIS Express and Kestrel Configuration
If you are using IIS Express for local development, certificate issues often stem from IIS Express using a different certificate than Kestrel. Make sure you trust the IIS Express development certificate, which is separate from the ASP.NET Core dev certificate:
// Check which certificate IIS Express is using
// Open Internet Information Services (IIS) Manager
// Go to Server Certificates
// Verify the IIS Express Development Certificate exists and is trusted
For Kestrel, you can specify a certificate explicitly in your configuration:
builder.WebHost.ConfigureKestrel(options =>
{
options.ConfigureHttpsDefaults(httpsOptions =>
{
httpsOptions.ServerCertificate = new X509Certificate2("path/to/cert.pfx", "password");
});
});
This gives you full control over which certificate Kestrel uses, which is useful when you have a specific certificate for local development or testing.
Troubleshooting Common Certificate Issues
Even after applying the fixes above, some certificate problems persist due to caching, expiration, or environment differences. Here are the issues I see most frequently and how to resolve them.
Certificate Expiration After One Year
The ASP.NET Core development certificate is valid for one year. When it expires, you start seeing the “remote certificate is invalid” error again without any code changes. The fix is straightforward: run dotnet dev-certs https --clean followed by dotnet dev-certs https --trust. I recommend setting a calendar reminder for this since it always seems to happen at the worst time.
Visual Studio Caching Old Certificates
Visual Studio sometimes caches certificate state from a previous session. If you have regenerated your dev certificate but Visual Studio still throws the error, try closing Visual Studio completely, deleting the bin and obj folders, and rebuilding. A full Visual Studio restart clears most certificate caching issues.
Missing Intermediate Certificates (PartialChain)
The PartialChain error means the server is not sending all the certificates needed to build a chain to a trusted root. This is a server-side configuration issue, not something you can always fix on the client. However, you can work around it by adding the intermediate certificate to your local trust store using X509ChainPolicy.ExtraStore:
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, errors) =>
{
if (errors == SslPolicyErrors.RemoteCertificateChainErrors)
{
var chainPolicy = new X509ChainPolicy
{
RevocationMode = X509RevocationMode.NoCheck,
VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority
};
chain.ChainPolicy = chainPolicy;
chain.ChainPolicy.ExtraStore.Add(additionalIntermediateCert);
return chain.Build((X509Certificate2)cert);
}
return errors == SslPolicyErrors.None;
};
For production, contact the API provider and ask them to include the full certificate chain in their server configuration. This is the proper fix for PartialChain errors.
Team Environment Inconsistencies
If the error happens on your machine but not your teammate’s, or vice versa, the issue is likely a difference in local certificate stores. Have everyone on the team run dotnet dev-certs https --clean and dotnet dev-certs https --trust to get to a consistent state. Document this in your project’s setup guide so new team members do not hit the same wall.
FAQs
How to fix invalid certificate error?
To fix an invalid certificate error, first identify the specific cause. For local development, run ‘dotnet dev-certs https –clean’ followed by ‘dotnet dev-certs https –trust’. For self-signed certificates, add the certificate to your system’s Trusted Root Certification Authorities store. For expired certificates, regenerate and re-trust the certificate. In development only, you can bypass validation using HttpClientHandler.ServerCertificateCustomValidationCallback.
How to solve net :: err_cert_invalid?
The net::err_cert_invalid browser error means the server’s SSL certificate failed validation. Common causes include an expired certificate, a self-signed certificate not in the trust store, a hostname mismatch, or an incomplete certificate chain. Fix it by ensuring the server has a valid, non-expired certificate from a trusted certificate authority, or by trusting the self-signed certificate locally. In Chrome, clearing cached certificate data in Settings > Privacy and security > Clear browsing data can resolve stale certificate states.
How to ignore invalid SSL certificate in C#?
In C#, you can ignore invalid SSL certificates by setting the ServerCertificateCustomValidationCallback on HttpClientHandler or SocketsHttpHandler. The simplest approach is: handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator. Alternatively, set the callback to always return true. Never use this bypass in production environments, as it removes all SSL/TLS security protections and enables man-in-the-middle attacks.
How to resolve the remote certificate is invalid according to the validation procedure?
This error resolves by addressing the specific validation failure. For UntrustedRoot errors, trust the certificate using ‘dotnet dev-certs https –trust’ or add it to the trusted root store. For PartialChain errors, ensure all intermediate certificates are available or add them via X509ChainPolicy.ExtraStore. For NotTimeValid errors, regenerate expired certificates. For HostnameMismatch, ensure the URL hostname matches the certificate’s subject name. Use a diagnostic ServerCertificateCustomValidationCallback to identify the exact SslPolicyErrors value before applying the fix.
Conclusion
Fixing “The Remote Certificate Is Invalid” error in C# comes down to identifying the specific cause and applying the right solution. For quick local development, the ServerCertificateCustomValidationCallback bypass works well. For a proper fix, use dotnet dev-certs to regenerate and trust your development certificate, or add self-signed certificates to your system trust store.
The key takeaways are: diagnose first using a diagnostic callback, bypass validation only in development, and use IHttpClientFactory with environment-based configuration for a clean, maintainable approach. For Docker and Linux environments, trust certificates at the OS level using update-ca-certificates or similar commands.
With these tools in hand, you can resolve any certificate validation error in your .NET projects and keep your development workflow moving without security compromises in production.