DB Contexts in IdentityServer
Entity Framework Core’s default behavior is to create all tables in the default database schema. When working with Duende IdentityServer, you may want to organize your data in separate schemas for better organization and security. IdentityServer’s standard configuration uses two separate DbContexts for different types of data. The ConfigurationDbContext
is responsible for storing configuration data such as clients, resources, and scopes. The PersistedGrantDbContext
stores operational data including grants, server sessions, and managed keys. By default, all tables are created in the default dbo
schema but you can modify this behavior using the options available for each context.
Modifying the Default Configuration
Using the standard pattern as found in the Duende Entity Framework project template the AddConfigurationStore
method accepts an action to modify settings on a ConfigurationStoreOptions
object. This is normally used to configure the DbContext’s connection but also exposes a DefaultSchema
property which handles changing the schema for all tables.
builder.Services.AddIdentityServer()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b =>
{
b.UseSqlServer(connectionString, dbOpts => dbOpts.MigrationsAssembly(typeof(Program).Assembly.FullName));
};
options.DefaultSchema = "config";
});
PersistedGrantDbContext
uses the same pattern with the AddOperationalStore
method.
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b =>
{
b.UseSqlServer(connectionString, dbOpts => dbOpts.MigrationsAssembly(typeof(Program).Assembly.FullName));
};
options.DefaultSchema = "ops";
});
The two contexts can share the same schema or each be set to a different schema.
Database Migrations
Running IdentityServer following these changes will cause runtime errors because the tables have not been moved to the new schemas yet. If using EF Core Migrations the changes can be added as a new migration and then applied to move the existing tables to their new schemas. Depending on your project setup this may vary, but for the standard Duende template the commands to run in the main project folder look like:
dotnet ef migrations add -c ConfigurationDbContext CustomSchema
dotnet ef migrations add -c PersistedGrantDbContext CustomSchema
The template includes an optional /seed
startup parameter that can be used to apply migrations directly from the IdentityServer application or scripts can be generated to execute against the database externally.
dotnet ef migrations script -c ConfigurationDbContext --idempotent --output Migrations/ConfigurationDb.sql
dotnet ef migrations script -c PersistedGrantDbContext --idempotent --output Migrations/PersistedGrantDb.sql
After the migrations have been applied, the tables should show under their new schemas while preserving any existing data.
Keep in mind that because this change is part of the code rather than the connection string, the schema name should be consistent across environments to avoid deployment issues. If required, the schemas can be set dynamically from configuration values but this will complicate applying migrations across the environments. Also remember that you may need to update your database permissions to reflect the new table structure: application database users will need access to the new schemas.
Code Versions
Example code is using .NET 8 with these library versions:
- Duende.IdentityServer.EntityFramework 7.0.7
- Microsoft.EntityFrameworkCore.SqlServer 8.0.10
- Microsoft.EntityFrameworkCore.Tools 8.0.10