Setting Up SAML Single Sign-On in ASP.NET with Duende IdentityServer

Summary: Duende IdentityServer supports SAML 2.0, allowing organizations to extend their existing Single Sign-On (SSO) solution to third-party SaaS applications, such as HubSpot, that only support the SAML protocol. By configuring IdentityServer as the SAML Identity Provider and registering the service provider's details, organizations can eliminate the need for users to manage separate credentials for platforms like HubSpot, Salesforce, or Workday. This integration, available in IdentityServer v8.0, transforms the IdentityServer into a SAML IdP that issues SAML assertions to service providers, streamlining the authentication process and improving security.
Your organization runs Duende IdentityServer as its central identity system. Your users authenticate through it, and your internal apps trust it. But then there's third-party software like HubSpot. Your marketing team lives in it, your sales team can't function without it, and everyone has yet another set of credentials to manage.
With OpenID Connect and OAuth, you can already integrate many third-party platforms into your SSO setup. But what happens when a platform only speaks SAML?
SAML 2.0 support is now available in Duende IdentityServer, so you can bring HubSpot and other SAML-only services under your existing Single Sign-On (SSO) umbrella. No more "I forgot my HubSpot password" tickets: you can log in with your existing credentials you use for other internal apps. And you can use the same approach we'll use in this blog post with any SAML 2.0-compliant SaaS platform, including Salesforce, ServiceNow, Workday, or Zendesk!
Let's walk through how to set it up.
Why SAML?
If you're already using IdentityServer, you're probably used to OpenID Connect (OIDC). It's the modern standard, and for new applications, it's still the right choice. But many SaaS platforms built their enterprise SSO integrations around SAML 2.0, and HubSpot is one of them. The same goes for Salesforce, ServiceNow, Workday, and dozens of others.
SAML 2.0 support in Duende IdentityServer (available with v8.0) bridges that gap. Your IdentityServer becomes a SAML Identity Provider (IdP), issuing SAML assertions to Service Providers (SPs) like HubSpot, without needing a separate identity system.
Configuring SAML in HubSpot And IdentityServer
Before getting started, make sure you have:
- Duende IdentityServer with a license that enables SAML 2.0 support
- A HubSpot account with SSO access (requires HubSpot's Enterprise plan)
- Access to HubSpot's Settings → Security → Login panel to consult configuration values and make updates
Step 1: Enable SAML in IdentityServer
SAML functionality is a part of Duende IdentityServer, but is not enabled by default. You'll need to register the SAML services in your startup configuration, using the AddSaml() extension method. This enables all SAML endpoints: metadata, sign-in, sign-out, and their callbacks.
Csharp
// Program.cs
builder.Services.AddIdentityServer(options =>
{
// ... your existing IdentityServer configuration
})
.AddSaml(); That's it. SAML signing requires an X.509 certificate, but when you use automatic key management or AddDeveloperSigningCredential() (which provide RSA keys without a certificate), IdentityServer automatically generates an X.509 container that wraps your existing RSA key material. You don't need to create or provide a certificate manually. In production, you'll likely want to use a properly issued certificate for your signing credential.
The metadata endpoint is immediately available at /Saml2. You'll need that URL shortly.
Step 2: Get HubSpot's SAML Details
In your HubSpot account, navigate to Settings → Security → Login. In the Configure single sign-on (SSO) section, select the All Other Identity Providers tab.

HubSpot will show you two values you need:
- Audience URI (Service Provider Entity ID): HubSpot's entity ID. It uniquely identifies HubSpot as the service provider.
- Sign on URL / ACS URL: The Assertion Consumer Service URL where IdentityServer will send SAML responses.
Copy both values. You'll plug them into your IdentityServer configuration next.
Step 3: Register HubSpot as a Service Provider
Back in your IdentityServer project, register HubSpot as a SAML Service Provider. Replace the placeholder values with the ones you copied from HubSpot:
Csharp
// Program.cs
builder.Services.AddIdentityServer()
.AddInMemoryIdentityResources(
[
new IdentityResources.OpenId(),
new IdentityResources.Email(),
new IdentityResources.Profile(),
])
.AddSaml()
.AddInMemorySamlServiceProviders(
[
new SamlServiceProvider
{
EntityId = "YOUR_HUBSPOT_AUDIENCE_URI",
DisplayName = "HubSpot",
// The ACS URL from HubSpot's SSO settings
AssertionConsumerServiceUrls =
[
new IndexedEndpoint
{
Location = "YOUR_HUBSPOT_ACS_URL",
Binding = SamlBinding.HttpPost,
Index = 0,
IsDefault = true
}
],
// HubSpot requires email-format NameID
DefaultNameIdFormat =
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
// Sign the assertion (HubSpot requirement)
SigningBehavior = SamlSigningBehavior.SignAssertion,
// Identity resources available for this SP
AllowedScopes = ["openid", "email", "profile"],
}
]);A few things to note:
-
AssertionConsumerServiceUrlsusesIndexedEndpointobjects that pair a URL with a binding, index, and default flag. All ACS endpoints must useSamlBinding.HttpPost(HTTP-Redirect is not supported for assertion delivery). -
DefaultNameIdFormatis set to the email address format. This tells IdentityServer to use the user's email claim as the SAML NameID, which is what HubSpot expects. -
SigningBehavioris set toSignAssertion, which signs the SAML assertion inside the response. This is the recommended default and what HubSpot requires. -
AllowedScopesdetermines which identity resources (and their claim types) are available for inclusion in assertions. Only identity resource names are valid here.
For production, you'll likely want to replace AddInMemorySamlServiceProviders with the EF Core store from Duende.IdentityServer.EntityFramework.Stores (via AddConfigurationStore()), or implement a custom ISamlServiceProviderStore.
Step 4: Point HubSpot to Your IdP
Back in HubSpot's SSO settings, provide HubSpot with your IdentityServer's SAML metadata URL:
https://your-identityserver.example.com/Saml2This XML-based metadata document contains everything HubSpot needs: your IdentityServer's SAML entity ID, signing certificate, and endpoint URLs. HubSpot can import it directly.
If you prefer to configure things manually, provide:
- Identity Provider Identifier (Issuer): Your IdentityServer's SAML entity ID (defaults to
{host}/Saml2) - Single Sign-On URL:
https://your-identityserver.example.com/Saml2/SSO - X.509 Certificate: Your signing certificate in PEM format (include the
-----BEGIN CERTIFICATE-----and-----END CERTIFICATE-----markers)
Once configured, click Verify in HubSpot to test the connection. HubSpot will redirect you to your IdentityServer login page. Authenticate, and if everything is wired up correctly, you'll land back in HubSpot, logged in.
Step 5: Login Page Compatibility
Your existing login page works with SAML without changes for the happy path: IdentityServer redirects to it with a returnUrl just like it does for OIDC. However, for the cancel/deny path, your login page needs to call DenyAuthenticationAsync on IIdentityServerInteractionService so IdentityServer can return the correct SAML error response to the SP. Without this, cancellation won't work for SAML flows.
Step 6: Test and Roll Out
Navigate to https://app.hubspot.com/login/sso and sign in. The flow looks like this:
- You enter your email on HubSpot's SSO login page
- HubSpot redirects to your IdentityServer with a SAML AuthnRequest
- You authenticate at IdentityServer (password, MFA, whatever your policies require)
- IdentityServer v8 issues a signed SAML assertion with your email as the NameID
- Your browser POSTs that assertion back to HubSpot's ACS URL
- HubSpot validates the signature, matches the email to a user account, and you're in
One important tip: exempt at least one Super Admin from SSO in HubSpot's settings. If your IdentityServer goes down for maintenance, you'll want a break-glass account that can still log in with a password. HubSpot supports this under the SSO configuration panel.
Wrapping Up
HubSpot is just one example. The same pattern (register the SP, map the claims, point the SP to your metadata) works for any SaaS platform that speaks SAML 2.0, like Salesforce, ServiceNow, Workday, or Zendesk.
With SAML 2.0 support in Duende IdentityServer, you don't need a separate identity provider for your enterprise SaaS integrations. Your existing IdentityServer handles OIDC for your custom apps and SAML for the SaaS platforms that require it. And if you have external SAML IdPs you need to federate with, IdentityServer can act as a SAML Service Provider too, consuming assertions from upstream SAML IdPs just like you'd use an external OIDC provider.
Check out the SAML documentation for deeper configuration options including extensibility interfaces, per-SP configuration, custom NameID generation, and service provider management.