Search code examples
c#identityserver4openid-connectidentitymodel

AddOpenIdConnect with manual Configuration - SecurityTokenSignatureKeyNotFoundException


Existing Systems

We are using Identity Server 4 to provide single sign on feature with Google, Azure, or other External providers without any problem. All we have to do is add client details and authority url or disco url (eg. .well-known/openid-configuration) and everything works as expected.

Scenario

One of our external Identity Provider said that they cannot provide the public Discovery Document url and they made it private only internally. Then they provided as the Json file (which contains the exact json texts provided by that url). So, we are trying to use the values in that json file to set all these endpoint urls and settings manually by using AddOpenIdConnect and OpenIdConnectConfiguration.

It correctly redirects to the external provider for Authorize requests and we can signin in the external system. But when the request comes back to our Idsrv4, it couldn't validate the id_token. We are getting SecurityTokenSignatureKeyNotFoundException. We did try to set the JwksUri but, still no luck.

I managed to replicate the same behaviour by using Demo Identity server and please see the following:

.AddOpenIdConnect("manualidsrv", "IdentityServer Manual", options =>
            {
                options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                options.SignOutScheme = IdentityServerConstants.SignoutScheme;

                options.Authority = "https://demo.identityserver.io/";
                options.ClientId = "login";
                options.ResponseType = "id_token";
                options.SaveTokens = true;

                options.Configuration = new OpenIdConnectConfiguration
                {
                    Issuer = "https://demo.identityserver.io",
                    JwksUri = "https://demo.identityserver.io/.well-known/openid-configuration/jwks",
                    AuthorizationEndpoint = "https://demo.identityserver.io/connect/authorize",
                    TokenEndpoint = "https://demo.identityserver.io/connect/token",
                    UserInfoEndpoint = "https://demo.identityserver.io/connect/userinfo",
                    EndSessionEndpoint = "https://demo.identityserver.io/connect/endsession",
                    ResponseTypesSupported =
                    {
                        "code",
                        "token",
                        "id_token",
                        "id_token token",
                        "code id_token",
                        "code token",
                        "code id_token token"
                    },
                    GrantTypesSupported = { 
                        "authorization_code",
                        "client_credentials",
                        "refresh_token",
                        "implicit",
                        "password",
                        "urn:ietf:params:oauth:grant-type:device_code"
                    },
                    ResponseModesSupported =
                    {
                        "form_post",
                        "query",
                        "fragment"
                    },
                    IdTokenSigningAlgValuesSupported = { "RS256" },
                    
            };

The error we are getting is

SecurityTokenSignatureKeyNotFoundException: IDX10501: Signature validation failed. Unable to match keys:
kid: '3BA75FA392E4DAFAC2737B5B4644AA85',
token: '{"alg":"RS256","kid":"3BA75FA392E4DAFAC2737B5B4644AA85","typ":"JWT"}.{"nbf":1596656241,"exp":1596656541,"iss":"https://demo.identityserver.io","aud":"login","nonce":"637322530390217907.xxx","iat":1596656241,"s_hash":"exiANrEFoXVDwA5BK1mGTg","sid":"D90FD8D4FA73AD590E3C53155375EA49","sub":"1","auth_time":1596652196,"idp":"local","name":"Alice Smith","given_name":"Alice","family_name":"Smith","email":"[email protected]","email_verified":true,"website":"http://alice.com","amr":["pwd"]}'.

I tried to check the jwksUri: https://demo.identityserver.io/.well-known/openid-configuration/jwks and I can see the correct kid '3BA75FA392E4DAFAC2737B5B4644AA85' there.

So, it seems to me that Idsrv4 is not loading these keys correctly if we set the Configuration manually.

There are some suggestion to load SigningKeys manually by using ConfigurationManager like the following:

new ConfigurationManager<OpenIdConnectConfiguration>($"DiscoveryEndpointUrl", new OpenIdConnectConfigurationRetriever());

However, since we don't have access to that endpoint url, it doesn't work for us.

Is there anyway to force Idsrv to load keys from jwksUri or provide the keys manually?

Could you please suggest to solve this signing key exception?


Solution

  • A workaround is perhaps to put the Discovery Document from the provider in a JSON document and just have it included in your IdentityServer as a static resource?. And then just add a link to that static endpoint in your configuration?

    I doubt IdentityServer care if that document is hosted locally or not.