Skip to content
We just launched Duende IdentityServer v7.2.0 and BFF v3.0. Check it out!

Duende IdentityServer v6.3 to v7.0

IdentityServer v7.0 includes support for .NET 8, pushed authorization requests, OpenTelemetry metrics, cleanup job improvements, and many other fixes and enhancements. Please see our release notes for complete details.

In your IdentityServer host project, update the version of the .NET framework. For example in your project file:

<TargetFramework>net6.0</TargetFramework>

would change to:

<TargetFramework>net8.0</TargetFramework>

Any NuGet packages that you are using that target an older version of .NET should also be updated. For example, the version of Microsoft.EntityFrameworkCore.SqlServer or Microsoft.AspNetCore.Authentication.Google should be updated. Depending on what your IdentityServer host project is using, there may or may not be code changes based on those updated dependencies.

In your IdentityServer host project, update the version of the Duende.IdentityServer package. For example in your project file:

<PackageReference Include="Duende.IdentityServer" Version="6.3.0"/>

would change to:

<PackageReference Include="Duende.IdentityServer" Version="7.0"/>

The schema updates required in this version are:

  • The server-side session entity in Duende.IdentityServer.EntityFramework now uses a 64-bit long as its primary key ( previously was a 32-bit int).
  • Two new properties have been added to the client model for PAR support.
    • Client.RequirePushedAuthorization is a new boolean property that controls if this client requires PAR. PAR is required if either the global configuration is enabled or if the client’s flag is enabled (this can’t be used to opt out of the global configuration). It is safe to initialize this column to false for existing clients, which will mean that the global configuration will be used.
    • Client.PushedAuthorizationLifetime is a new nullable integer property that controls the lifetime of pushed authorization requests (in seconds) for a client. If this lifetime is set, it takes precedence over the global configuration. It is safe to initialize this column to null for existing clients, which means the global configuration is used.
  • A new table has been added to store pushed authorization requests. This new table contains a hashed identifier, the pushed parameters (as a string, serialized and data protected), and the expiration time of the request.

IdentityServer is abstracted from the data store on multiple levels, so the steps involved in updating your data store will depend on your implementation details.

The core of IdentityServer is written against the store interfaces, which abstract all the implementation details of actually storing data. If your IdentityServer implementation includes a custom implementation of those stores, then you will have to determine how best to include the changes in the model in the underlying data store and make any necessary changes to schemas, if your data store requires that.

We also provide a default implementation of the stores in the Duende.IdentityServer.EntityFramework package, but this implementation is still highly abstracted because it is usable with any database that has an EF provider. Different database vendors have very different dialects of sql that have different syntax and type systems, so we don’t provide schema changes directly. Instead, we provide the Entity Framework entities and mappings which can be used with Entity Framework’s migrations feature to generate the schema updates that are needed in your database.

To generate a migration for the new columns, run the command below. Note that you might need to adjust paths based on your specific organization of the migration files.

Terminal
dotnet ef migrations add Update_DuendeIdentityServer_v7_0 -c ConfigurationDbContext -o Migrations/ConfigurationDb
dotnet ef migrations add Update_DuendeIdentityServer_v7_0 -c PersistedGrantDbContext -o Migrations/PersistedGrantDb

The ServerSideSession.Id property has been changed from int to long. The generated migration handles the data type change but does not take into account that this column is the primary key for the table. If the primary key constraint is not removed, running the migration will fail. The primary key of the table needs to be dropped before the type is altered and then recreated. The easiest way to do so is to update the generated migration file:

// Add this line before AlterColumn
migrationBuilder.DropPrimaryKey("PK_ServerSideSessions", "ServerSideSessions");
// This should already be in the generated code
migrationBuilder.AlterColumn<long>(
name: "Id",
table: "ServerSideSessions",
type: "bigint",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("SqlServer:Identity", "1, 1")
.OldAnnotation("SqlServer:Identity", "1, 1");
// Add this after AlterColumn
migrationBuilder.AddPrimaryKey("PK_ServerSideSessions", "ServerSideSessions", "Id");

Once you’ve updated that migration, both migrations should be applied to your database:

Terminal
dotnet ef database update -c ConfigurationDbContext
dotnet ef database update -c PersistedGrantDbContext

Some organizations prefer to use other tools for managing schema changes. You’re free to manage your schema however you see fit, as long as the entities can be successfully mapped. Even if you’re not going to ultimately use Entity Framework migrations to manage your database changes, generating a migration can be a useful development step to get an idea of what needs to be done.

Only impacts particular customizations or edge cases

Section titled “Only impacts particular customizations or edge cases”
  • The DefaultCorsPolicyService now depends on the IConfigurationDbContext directly, instead of taking a dependency on the IServiceProvider and resolving that DbContext from it. If you have a customized CORS implementation that derives from the DefaultCorsPolicyService, you need to update the constructor of your derived class to use the IConfigurationDbContext.
  • The DPoPProofValidationContext has been refactored. Instead of the Client property, we now put the relevant details (expiration validation mode and clock skew) directly in the context. We also have added the HTTP method and URL to the context. If you have a custom implementation of the IDPoPProofValidator or a class that derives from the DefaultDPoPProofValidator, update your usage of the context appropriately.
  • The DefaultTokenService no longer includes an IHttpContextAccessor. This member was unused by the default implementation and marked as obsolete. Customizations that derive from the DefaultTokenService no longer need to pass the accessor to the base constructor. If such a customization needs the accessor, add it to the derived class.
  • The ValidatedAuthorizeRequest.RequestedResourceIndicators property was misspelled and has been renamed RequestedResourceIndicators.
  • The reference token store now includes the session id when revoking reference tokens. Implementors of IReferenceTokenStore should update their implementation of token revocation to include the session id.
  • Invalid prompt modes now cause validation errors that result in an HTTP 400 (Bad Request). Previously, invalid prompt modes were ignored. This complies with updates to the OpenID Connect specification.
  • A new interface IIdentityServerTools has been introduced for the IdentityServerTools helper class to allow mocking. Update any direct references to IdentityServerTools to IIdentityServerTools.
  • IAuthorizationParametersMessageStore is deprecated. PAR is a more robust/standardized approach to get similar benefits.

  • The IHttpContextAccessor in the EndSessionRequestValidator is unused and has been marked as obsolete. It will be removed in a future version.

  • The obsolete IdentityServerOrigin constant has been removed.
  • Several obsolete extension methods on HttpContext have been removed. These methods are replaced by methods in IServerUrls and IIssuerNameService. See #1457
    • HttpContext.GetSchemeSupportsSignOutAsync is replaced by IAuthenticationHandlerProvider.GetHandlerAsync (you will also need to check if the handler implements IAuthenticationSignOutHandler).
    • HttpContext.GetIdentityServerOrigin and HttpContext.SetIdentityServerOrigin are replaced by IServerUrls.Origin.
    • HttpContext.GetIdentityServerBasePath and HttpContext.SetIdentityServerBasePath are replaced by IServerUrls.BasePath.
    • GetIdentityServerHost is replaced by IServerUrls.Origin
    • GetIdentityServerBaseUrl is replaced by IServerUrls.BaseUrl
    • GetIdentityServerRelativeUrl is replaced by IServerUrls.GetIdentityServerRelativeUrl
    • GetIdentityServerIssuerUri is replaced by IIssuerNameService.GetCurrentAsync
    • RedirectToAbsoluteUrl is replaced by redirecting to a call to IServerUrls.GetAbsoluteUrl.
  • The obsolete and unused IUserSessionExtensions interface has been removed.
  • The obsolete IPrincipal.GetName and IIdentity.GetName extension methods have been removed. Use ClaimsPrincipal.GetDisplayName instead.
  • The obsolete ResourceValidationRequest.IncludeNonIsolatedApiResources has been removed. This flag was no longer used.

That’s it. Of course, at this point you can and should test that your IdentityServer is updated and working properly.

Step 6: Troubleshooting .NET 8 Issues Optional

Section titled “Step 6: Troubleshooting .NET 8 Issues ”Optional

You are now done with everything related to the IdentityServer upgrade, but we would also like to add a references to breaking changes in .NET 8 and associated libraries that are likely to affect the IdentityServer setup.

  • Entity Framework Core 8 has some performance improvements in the query generation for Microsoft SQL Server that relies on database features that requires a database compatibility level of at least 130. This can cause errors on database access like Microsoft.Data.SqlClient.SqlException (0x80131904): The syntax near ’$’ is incorrect. or Microsoft.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near the keyword ‘WITH’. Please see https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/breaking-changes#mitigations for more information.
  • For container deployments, the default ASP.NET Core port changed from 80 to 8080. This might require configuration updates to either continue using port 80 or to migrate to using 8080.
  • IdentityServer and the ASP.NET Authentication packages all depends on the Microsoft.IdentityModel.* packages. With packages that are brought in as transient dependencies there is less control of the versions being pulled in. If different packages from the Microsoft.IdentityModel.* family end up having different versions, there will be odd bugs. We’ve seen reports where the refresh token isn’t stored and where the OIDC handler fails to redirect to an OIDC Provider because it failed reading the discovery document. Always ensure that all Microsoft.IdentityModel. packages are of exactly the same version*. If they are not, you might need to make an explicit <PackageReference> to pin an exact version.