Search code examples
.net-coreidentityserver4

Best practice on multiple IdentityServer4 services


I have two identityservers and one Web API. What Im trying to do is having the API authenticate with one or both of the IdentityServers and being able to switch if one goes down. If possbile I would also like to be able to add a new IdentityServer at runtime.

Is there any best practice here?

As of now it looks like this.

        app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
        {
            Authority = $"http://localhost:5000",
            ScopeName = "my.scope",
            RequireHttpsMetadata = false,
            ScopeSecret = "secret",
        });

If I shut down the IdentityServer at port 5000 I can't use the API anymore. Which is to be expected.


Solution

  • Im not sure if this is a good way to solve it. But it's one way. I ask my routing service for the "first identityservice" to set the Authroity in options. And then I add a custom IntrospectionBackChannelHandler

            app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
            {
                Authority = $"http://{v.Address}:{v.Port}",
                IntrospectionBackChannelHandler = new CustomIntrospectionBackChannelHandler(consulService)
    

    Since all my identity servers look the same but are on different addresses I dont really have to bother to do the Authority thing again.

    Inside the custom Introspect.... I check each introspect and send it to the "correct" identityserver. If its not working I try another identityserver.

    var qs = await request.Content.ReadAsStringAsync(); var queryDic = QueryHelpers.ParseQuery(await request.Content.ReadAsStringAsync());

            var token = queryDic["token"];
            var client_id = queryDic["client_id"];
            var client_secret = queryDic["client_secret"];
            var iRequest = new IntrospectionRequest
            {
                ClientId = client_id,
                ClientSecret = client_secret,
                TokenTypeHint = "access_token",
                Token = token
            };
    
            IntrospectionResponse result = null;
    
            var svc = await _Consul.GetService(OrbitServices.IdentityServer);
            result = await TrySendAsync(iRequest, svc);
            if (!result.IsActive && result.IsError)
            {
                svc = await _Consul.GetService(OrbitServices.IdentityServer, true);
                result = await TrySendAsync(iRequest, svc);
            }
    
            var message = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent(result.Raw, Encoding.UTF8, "application/json")
            };
    
            return message;