External providers
Users can sign in somewhere else — a corporate directory, a social login, a partner's identity provider — and arrive
here signed in. In the other direction, this server can be the SAML 2.0 identity provider a partner application signs
its users in against. This page registers each kind; a federation gateway puts them together —
many providers behind one server, one identity downstream, and single sign-out across the chain. The code on this page is included from
samples/ExternalProviders,
which a test boots and asks for its SAML metadata.
dotnet add package Fdyay.IdentityServer.Federation
dotnet add package Fdyay.IdentityServer.Saml
An OpenID Connect provider
// The sign-in page lists every external scheme; a user who picks one is sent there, and comes back to this
// server's own external-sign-in callback, which signs them in here.
builder.Services.AddAuthentication()
.AddExternalOpenIdConnect("contoso", "Contoso (Entra ID)", options =>
{
options.Authority = "https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0";
// The registration at the provider: the id from appsettings.json, the secret from user secrets or the
// environment (Federation__Contoso__ClientSecret), never from a file that is committed.
options.ClientId = builder.Configuration["Federation:Contoso:ClientId"];
options.ClientSecret = builder.Configuration["Federation:Contoso:ClientSecret"];
options.ResponseType = "code";
options.CallbackPath = "/signin-contoso";
options.Scope.Add("email");
options.MapInboundClaims = false;
});
AddExternalOpenIdConnect is
ASP.NET Core's OpenID Connect handler, pointed at this server's external cookie: the sign-in page offers it, the user
signs in there, and the bundled external sign-in page finds or provisions the local user and signs them in here. Each
provider needs its own CallbackPath. A client can be held to particular providers with
IdentityProviderRestrictions, or sent straight to one with an idp: value in
acr_values. Providers that change at runtime can be stored as rows instead: see AddDynamicProviders and
AddDynamicOidcProviders.
A SAML 2.0 identity provider
// An upstream SAML 2.0 identity provider: this server is its service provider, and the user it vouches for is
// signed in here exactly as one from an OpenID Connect provider is.
builder.Services.AddAuthentication()
.AddExternalSaml2("fabrikam", "Fabrikam (SAML)", options =>
{
options.SpEntityId = "https://localhost:5001/saml/fabrikam";
options.IdpEntityId = "https://idp.fabrikam.example.com/saml";
options.IdpSingleSignOnUrl = "https://idp.fabrikam.example.com/saml/sso";
options.IdpSingleLogoutUrl = "https://idp.fabrikam.example.com/saml/slo";
// The identity provider's public certificate, which verifies the assertions it sends.
options.IdpSigningCertificate = X509CertificateLoader.LoadCertificateFromFile(
Path.Combine(builder.Environment.ContentRootPath, "fabrikam-idp-signing.cer"));
options.CallbackPath = "/signin-fabrikam";
});
AddExternalSaml2 registers this
server as a SAML service provider to an upstream identity provider — native SAML, with no third-party library. The
assertion is verified against IdpSigningCertificate and its issuer,
audience, recipient and InResponseTo checked before the user is signed in — from the browser that started the sign-on,
once (what an assertion has to be). Every setting is listed under
SamlSpOptions.
A partner application signing in here over SAML
// The other direction: this server as a SAML 2.0 identity provider, and a partner application registered as a
// service provider that signs its users in here. Metadata is served at /saml/metadata.
identityServer.AddSaml(
options => options.EntityId = "https://localhost:5001/saml",
new SamlServiceProvider
{
EntityId = "https://app.tailspin.example.com/saml",
AssertionConsumerServiceUrl = "https://app.tailspin.example.com/saml/acs",
SingleLogoutServiceUrl = "https://app.tailspin.example.com/saml/slo",
// The identity scopes whose claims may travel in the assertion as attributes.
AllowedScopes = { "openid", "profile", "email" },
// Verifies the partner's signed AuthnRequests, which are required by default.
RequestSigningCertificate = X509CertificateLoader.LoadCertificateFromFile(
Path.Combine(builder.Environment.ContentRootPath, "tailspin-sp-signing.cer")),
});
AddSaml makes this server a SAML 2.0
identity provider: single sign-on at /saml/sso, single logout at /saml/slo, and metadata at /saml/metadata. Each
SamlServiceProvider is one partner: where its assertions go, which identity scopes'
claims they may carry, and the certificate its signed requests are verified with. Without
SigningCertificate the assertions are signed with the
server's own managed key. The server-wide settings are under SamlOptions.