IdentityServer4 was designed to be decoupled from the datastore used to persist the data, for that you will find many storage libraries that you can choose from to save IdentityServer data to any database of your choice. in this article we will see how we can integrate MongoDB With IdentityServer4 to be used as the persistence mechanism for its data.
Note
if you are not interested in manually configuring the integration with MongoDB you can find a quick starter template on my Github that you can use as a starting point for your project.
I will assume that you already have IdentityServer4 configured in your project. if not, prepare one first and then continue.
also, you need to have a MongoDB server installed and running in order to test your integration.
Installing the Package
In this article we will use a package developed by me, you can find it in my Github, and also in NuGet.
to install the package using the Package Manager Console:
Install-Package YoussefSell.IdentityServer4.MongoDB
or with the Package Manager:

Stores Configurations
With the package installed, we can start the configuration of IdentityServer4 with MongoDB.
we should mention that in IdentityServer4 There are two types of data that should be persisted.
- The first type is the configuration data including resources and clients.
- The second type is operational data produces by IdentityServer4 as it’s being used like tokens, codes, and consents.
and in order for IdentityServer to access this data, it exposes multiple stores interfaces each for a specific type of data, for instance, we have IClientStore to access the Clients data, IResourceStore to access resources, and so on.
so the package that we have installed is just an implementation of this Stores interfaces using MongoDB.
if you need more details on how you could do it your self there is a great article by Scott Brady (Creating Your Own IdentityServer4 Storage Library) where he explains in detail how you could build a storage library for IdentityServer4, give it a look.
so let’s get started, first open the file where you have the IdentityServer4 configuration and replace the following methods:AddInMemoryClients
, AddInMemoryIdentityResources
, and AddInMemoryApiResources
with:

as you can see both functions required you to pass in the name of the database and the connection string. and they also have an overload where you can do a more complex configuration. for now, let’s stick with this simple integration, and we will see the other one soon.
next, let’s add a function to populate the database with the initial data, some clients, and resources, the data is located in a static class “Config” that comes by default with the IdentityServer4 template.
private void InitializeDatabase(IApplicationBuilder app)
{
using var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope();
var clientsCollection = serviceScope.ServiceProvider.GetRequiredService<IMongoCollection<ClientEntity>>();
if (!clientsCollection.AsQueryable().Any())
{
clientsCollection.InsertMany(Config.Clients
.Select(client => client.ToEntity()));
}
var identityResourceCollection = serviceScope.ServiceProvider.GetRequiredService<IMongoCollection<IdentityResourceEntity>>();
if (!identityResourceCollection.AsQueryable().Any())
{
identityResourceCollection.InsertMany(Config.IdentityResources
.Select(resource => resource.ToEntity()));
}
var apiScopeCollection = serviceScope.ServiceProvider.GetRequiredService<IMongoCollection<ApiScopeEntity>>();
if (!apiScopeCollection.AsQueryable().Any())
{
apiScopeCollection.InsertMany(Config.ApiScopes
.Select(resource => resource.ToEntity()));
}
}
then call this action in the Configure method of your Startup class:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// this will do the initial DB population
InitializeDatabase(app);
// other code ...
}
If you run the app and check your database you will see that the data has been added successfully.

More control
Now that we’re done with the simple integration, let’s see how we can do a more advanced configuration using the other overloads, if you checked the IntelliSense you will see that both methods, AddOperationalStore
and AddConfigurationStore
take an action with StoreOptions which gives you full control to configure your database and collection.
the StoreOptions consist of two parts:
– DatabaseOptions: to configure your database, it will allow you to set the database name, pass a MongoClientSettings and a MongoDatabaseSettings.

– Collections configurations: to configure the collection for each data type, so that base on the store options you will have a number of collections each used to persist a specific type of data.

the collection configuration gives you access to set the collection name, pass a MongoCollectionSettings, and configure default indexes to be created with the collection.
one more configuration you can do only on the OperationalStore is to configure the TokenCleanup operation with the properties
– EnableTokenCleanup: true to enable the token clean up.
– TokenCleanupInterval: the token cleanup interval (in seconds).
– TokenCleanupBatchSize: number of records to remove at a time.
here is a sample code on how you could achieve this configuration using the last method:
public void ConfigureServices(IServiceCollection services)
{
// other code ...
const string databaseName = "identityServer";
const string connectionString = @"mongodb://localhost:27017";
var mongoClientSettings = MongoClientSettings.FromConnectionString(connectionString);
var mongoDatanaseSettings = new MongoDatabaseSettings
{
// your database settings code
};
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddTestUsers(TestUsers.Users)
// add the operational store
.AddOperationalStore(options =>
{
// database options
options.DatabaseOptions = new DatabaseOptions(
databaseName: databaseName, // your database name
mongoClientSettings: mongoClientSettings, // your MongoClientSettings instance
mongoDatabaseSettings: mongoDatanaseSettings); // your MongoDatanaseSettings instance
options.DeviceFlowCodes = new CollectionConfiguration<DeviceCodeEntity>(
collectionName: "DeviceFlow",
collectionSettings: new MongoCollectionSettings
{
// your collection settings
});
// ... other collections configurations
// token cleanup configuration
options.EnableTokenCleanup = true;
options.TokenCleanupBatchSize = 100;
options.TokenCleanupInterval = 3600;
})
// add the configuration store
.AddConfigurationStore(databaseName, connectionString);
// other code ...
}
so as you can see you have full access to your database and collections configuration. and if you need to go with the simple approach you have that too.