Connecting two instances of IdentityServer 4 using the ComponentSpace SAML v2.0 for .NET Core and the Rock Solid Knowledge SAML v2.0 for .NET Core stack

This follows on from this article.

That article use the ComponentSpace (CS) stack on both sides. Here we are doing the same thing but using two different stacks, the other being the offering from Rock Solid Knowledge (RSK). There is a good overview here for RSK with the source code here.

Just FYI, the respective Twitter feeds are @ComponentSpace and @rskltd.

Thanks to ComponentSpace and Rock Solid Knowledge for their help.

Essentially what we have is:

CS test client using SAML → idsrv4 running as a IDP and a SP → idsrv4 running as a IDP

The idsrv4 using CS runs as a IDP and a SP on port 6000 so lets call that idsrv4:6000. The idsrv4 using RSK runs just as a IDP on port 5000 so lets call that idsrv4:5000.

So expanding the above we get:

CS test client using SAML → idsrv4:6000 running as a CS IDP → idsrv4:6000 running as an CS SP → idsrv4:5000 running as a RSK IDP.

The RSK metadata is at:


We can see from the metadata that the entityID is:


and the SSO endpoint is:

<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:5000/saml/sso" />

The first part of the path i.e. connecting CS test client using SAML → idsrv4:6000 running as a CS IDP is exactly the same as the original article (link above) so you can get the configuration from there.

The only difference is the RSK certificate:

"FileName": "certificates/idsrv3test.cer"

As usual, all the code is in the gist.

For idsrv4:6000:


"Description": "IdentityServer4-RSK",
"Name": "http://localhost:5000",
"PartnerCertificates": [
"FileName": "certificates/idsrv3test.cer"
"SignAuthnRequest": true,
"SingleSignOnServiceUrl": "http://localhost:5000/saml/sso"

In Startup.cs in the AddExternalIdentityProviders section:

.AddSaml("idsrv4", "IdentityServer4", options =>
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.AssertionConsumerServicePath = "http://localhost:5000/saml/sso";
options.PartnerName = () => "http://localhost:5000";

For idsrv4:5000:

in Config.cs — GetClients:

// SAML client
new Client
ClientId = "https://IdentityServer4",
ClientName = "idsrv4 CS",
ProtocolType = IdentityServerConstants.ProtocolTypes.Saml2p,
AllowedScopes = {"openid", "profile"}

Note the scopes. This defines the claims that will be sent to the client.

And in GetServiceProviders:

public static IEnumerable<ServiceProvider> GetServiceProviders()
return new[]
new ServiceProvider
EntityId = "https://IdentityServer4",
AssertionConsumerServices =
{new Service(SamlConstants.BindingTypes.HttpPost, "http://localhost:6000/SAML/AssertionConsumerService")},
SigningCertificates = {new X509Certificate2("sp.cer")}

Note that you have to copy the certificates (sp.cer and idsrv3test.cer) over.

Running it:

Click the SSO button.

Click the “IdentityServer4” button.

This is the login screen for the RSK stack.

Authenticate as bob / bob.


Note that the user’s ID is “88421113”.

new TestUser{SubjectId = "88421113", Username = "bob", Password = "bob", 
Claims =
new Claim(JwtClaimTypes.Name, "Bob Smith"),
new Claim(JwtClaimTypes.GivenName, "Bob"),

This is derived from TestUsers.cs.

All good!