skip to Main Content

We are using the deprecated IdentityServer4. We have an client application and an IdentityServer. When the client application authenticates, the client sends it´s secret to the IdentityServer. The IdentityServer loads the secrets from it´s own database (table: ClientSecrets, Column: Value) and compares them with the secrets from the client application for authentication. How can we bypass the database, so that the IdentityServer uses an secret, that is defined in C#-code instead querying ClientSecrets.Value from the database for the authentication process? Perhaps is there any hook available?

enter image description here

2

Answers


  1. I have used it in the past. If I remember correctly, Identityserver4 takes the clientsecret(aka password) and generates a token during the authentication step. The users then take that token(valid for 60min, by default) and sends it as part of their header request. Identityserver takes this token, decrypts it and validates and compares the secret with the existing value in the db.

    Based on your question, I am assuming you have a separate db setup for Identityserver4. But, in our setup, we have added the Identityserver specific tables on top of our existing database, according to how Identity wanted us to name, seed and design them. That way, identity can work with existing users on the database. Hope that helps.

    Login or Signup to reply.
  2. To achieve what you’re asking for — bypassing the database and using client secrets defined in C# code — you can implement a custom IClientStore. This allows you to define hardcoded clients in memory and completely avoid querying a database.
    Create a class that implements IClientStore. This class will store clients in a dictionary for quick lookup:

    public class CustomClientStore : IClientStore
    {
        // Hardcoded clients stored in memory
        private static readonly Dictionary<string, Client> HardcodedClients = new()
        {
            {
                "example-client", new Client
                {
                    ClientId = "example-client",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = { new Secret("hardcoded-secret".Sha256()) },
                    AllowedScopes = { "api1" }
                }
            },
            {
                "another-client", new Client
                {
                    ClientId = "another-client",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets = { new Secret("another-secret".Sha256()) },
                    AllowedScopes = { "api1" }
                }
            }
        };
    
        public Task<Client> FindClientByIdAsync(string clientId)
        {
            // Retrieve the client from the dictionary
            return Task.FromResult(HardcodedClients.TryGetValue(clientId, out var client) ? client : null);
        }
    }
    

    In your Program.cs file, register CustomClientStore so that IdentityServer4 uses it to retrieve clients:

    builder.Services.AddScoped<IClientStore, CustomClientStore>();
    

    Finally, create a service or a controller that uses CustomClientStore to validate clients. This ensures that validation is consistent with your hardcoded configuration:

    public class ClientService
    {
        private readonly CustomClientStore _clientStore;
    
        public ClientService(CustomClientStore clientStore)
        {
            _clientStore = clientStore;
        }
    
        public async Task<bool> ValidateClientAsync(string clientId, string clientSecret)
        {
            // Retrieve the client using CustomClientStore
            var client = await _clientStore.FindClientByIdAsync(clientId);
            if (client == null)
            {
                return false; // Client not found
            }
    
            // Validate the provided secret
            foreach (var secret in client.ClientSecrets)
            {
                if (secret.Value == clientSecret.Sha256())
                {
                    return true; // Valid secret
                }
            }
    
            return false; // Invalid secret
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search