Search code examples
c#identityserver4

IdentityServer 4 with EntityFramework - Getting client properties?


I'm using Identity Server 4 with EntityFramework for configuration. I now want to get the current client from the login-page. I was able to get the client ID from the return url parameter. And then I'm using ConfigurationDbContext to get the client from the database.

But on the client, the Properties property is always null, even if I add a property on that client in the database.

How do i get hold of the properties for a client?


Solution

  • Instead of using ConfigurationDbContext directly, there's a handy interface in the IdentityServer project that's more abstract: namely IClientStore. This interface itself contains a single function: FindClientByIdAsync, which can be used for obtaining a Client. Client includes a number of properties, including:

    • ClientName
    • LogoUri
    • Properties

    You can get an instance of IClientStore using DI (I expect you're already doing this for ConfigurationDbContext). Once you have this, just call FindClientByIdAsync accordingly:

    var yourClient = await clientStore.FindClientByIdAsync(clientId);
    

    When using this approach, Properties will be populated, as expected.


    In order to explain why your original approach isn't giving the expected results, we need to understand how Entity Framework Core handles loading related data. Simply put, when retrieving a Client entity (this a different Client class to that I've used above), the navigation properties (e.g. Properties) are not populated by default, which is why you see null. I strongly recommend that you read the Loading Related Data docs if you're more interested in how this works.

    The Entity Framework Core implementation of IClientStore (ClientStore) handles this loading of related data for you. Here's a code snippet from the source itself:

    public Task<Client> FindClientByIdAsync(string clientId)
    {
        var client = _context.Clients
            // ...
            .Include(x => x.Properties)
            .FirstOrDefault(x => x.ClientId == clientId);
    
        var model = client?.ToModel();
    
        return Task.FromResult(model);
    }
    

    The Include(x => x.Properties) is what takes care of fetching the Properties from the database.