SAML2 for Thinktecture IdentityServer 3 with Kentor.AuthServices

Using the Kentor.AuthServices SAML2 Service Provider with Thinktecture IdentityServer 3 bridges the gap between SAML2 and OAuth2/OpenID Connect. Thinktecture IdentityServer 3 support clients using the modern OAuth2 and OpenID Connect protocols. It can either have a local account database through e.g. ASP.NET Identity, or use external authentication services. By registering Kentor.AuthServices with IdentityServer, IdentityServer can authenticate to a SAML2 Idp.

I know that SAML2 is often regarded as legacy, but the truth is that there is still vast amounts of infrastructure out there that supports SAML2, but has not yet taken the leap to OpenID Connect. When the client applications prefer modern standards, a bridge between them is needed. With Kentor.AuthServices, Thinktecture IdentityServer can be that bridge.

Get It Running

To add SAML2 to IdentityServier, changes are needed in three places: Installing the Kentor.AuthServices.Owin package, alter the startup configuration method for IdentityServer and add two lines to the web/app.config file.

IdentityServer configures external authentication in a callback method, which is registered in IdentityServerOptions.AuthenticationOptions.IdentityProviders. In that method, additional owin middleware to use for authentication can be used. Kentor.AuthServices is registered in the same way as the owin middleware is registered in any other owin application. In this example (with Kentor.AuthServices 0.12.0) everything is done in code, but using the web/app.config is also supported. Change the options constructor parameter to true to load the config from file.

var authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
  SPOptions = new SPOptions
    EntityId = new EntityId("")
  SignInAsAuthenticationType = signInAsType,
  AuthenticationType = "saml2p",
  Caption = "SAML2p",
authServicesOptions.IdentityProviders.Add(new IdentityProvider(
  new EntityId(""),
    LoadMetadata = true,

For the web/app.config, there must be a <System.identityModel> section. It might be empty, but it has to be there.As of AuthServices 0.15.0 this is no longer needed.
First register the section.

  <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=, Culture=neutral, PublicKeyToken=B77A5C561934E089" />

Then add an empty section.


With these changes, IdentityServer will offer SAML2p as an external authentication type, redirecting to the AuthServices Stub Idp. As it allows the user to enter any name id, I wouldn’t recommend using it in production code…

No Discovery Service (yet)

There is unfortunately one limitation for this setup: Discovery Service won’t work. This is due to AuthServices not handling owin authentication state across the redirect to the discovery service. It is on the todo list (#182), but until it is fixed it simply won’t work.


  1. Nice one :)
    Especially happy to see that we can now do the configuration purely in code; I have a scenario where there will be several SAML providers (it’s for a multi-tenanted solution) so it’s much nicer if I can manage the IdPs in a database.

    I do have a question, though; Why do we need to pass a dummy SPOptions with a dummy EntityId to the Options object? I do know that the CreateClaims method fails if you don’t, but it seems a bit odd?

    Thanks for all your hard work – you have saved me a ton of time.


    1. There are two different EntityIds. The SpOptions.EntityId is the id of the service provider. It is used to validate the audience restriction condition of the saml assertion. Then each identity provider is identified by an entity id too.

    2. Hi Abel , I found your post very useful ,

      Have the following questions
      1) so with this bridge provider, is the following scenario possible thinktecture identityserver (as federation provider) + SAML2 Identity provider (at partner site)
      2) Can you clarify on the comment
      ” As it allows the user to enter any name id, I wouldn’t recommend using it in production code”


      1. 1. Yes, it’s possible to use that setup. It would look something like this

        Application — (OpenID Connect) —> IdentityServer 3 — (SAML2) —> Partner IDP.

        The application would authentication with IdSrv3 with one of the protocols supported by IdSrv3. Then IdSrv3 would use SAML2 to authenticate the user against an external IDP.

        2. That comment refers to the stub idp at, that the sample code uses. The stub idp is a test idp and is not meant for production use. If you use a real idp in the configuraiton it is of course safe.

  2. Hi Andres, I might have misunderstood what the Kentor provider does then.

    my scenario is –
    1) RP is a .net web application using WIF so sign in protocol is ws-fed
    2) IP is thinktecture identityserver v2

    currently for partners we maintain user credentials , strategy is to stop that approach and implement Federated SSO using partners IDP. Partner IDP is on SAML2p.
    I believe idendityserver v2 does not SAML2p sign in protocol but does support SAML 2 token type.

    How can i leverage the Kentor provider to accomplish the above

    1. This post is only related to IdentityServer v3. I have unfortunately no idea of IdentityServer v2.

      What you want to do should be possible with IdentityServer v3, through the WSFederation plugin.

      1. RP would authenticate against IdentityServer v3 through ws-fed.
      2. The IdentityServer v3 would authenticate the user against the external idp by using the Kentor.AuthServices SAML2 middleware with IdentityServer v3, as described in this post.

  3. Good stuff, Anders.

    Question: I need to be able to do an IdP-initiated SSO by sending a SAML response containing a SAML assertion to an SP. We’re using Identity Server v3 OIDC for our normal authentication. Can we use your module to initiate this SSO?

    1. AuthServices supports IDP-initiated SSO (unsolicited responses) for all three API modules (MVC controller, Http module and Owin middleware). However, as far as I know there is no support in Identity Server for that. Even though AuthServices loaded into Identity Server will happily accept the incoming assertion, there is no way for Identity Server to know where to forward the call.

      If you want IDP-initiated SSO you would have to load AuthServices directly into your application and bypass Identity Server in that scenario.

      1. Wondering if you can help me make some sense of this — it looks like Identity Server 3 does indeed support this via a new API method available within it — IssueLoginCookie. See the following post/pull request:

        I would be again happy to do a write up if I can get something working as I suspect this would help other people as well.

      2. Erik, that’s news to me. It would be very appreciated if you could add information on how to do that in the AuthServices documentation directly in the github repo (submit a pull request)

  4. You are missing information about asc endpoint routing. In the newest version of kentor authservices it’s /AuthServices/Acs.

  5. Hello,

    I’m not sure I’m understand the fonctionnality of the kentor-authservices.

    I would like to expose a Saml Endpoint with my IdentityServer v3 to allow SSO between my different Apps & a SaaS Application called FreshDesk. Is the kentor-authservices will allow me to do that? (so act as a plugin and not as an external idp)?

    Thanks for you help.

    1. Kentor.AuthServices is unfortunately only a SP implementation, meaning it can be used to make IdSrv3 authenticate with an external Idp. It cannot act as a plugin to IdSrv3 to make SAML2 applications able to authenticate against IdSrv3.

    1. Yes, this would be possible, but would require some work, especially the part to get IdentityServer3 to validate the SAML2 assertion.

      It is also a bit unclear to me what the audience settings should be in the SAML2 assertion. Should it be aimed for the client application, or for the OAuth2 server?

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.