Migrate to OpenIddict 4.0
+ +What's new?
+The most important changes introduced in 4.0 can be found here.
+Note
Unless you're using MongoDB, migrating to OpenIddict 4.0 doesn't require making changes to your database.
+Update your packages references
+For that, update your .csproj
file to reference the OpenIddict
4.x packages. For instance:
<ItemGroup>
+ <!-- OpenIddict 3.x: -->
+ <PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
+ <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
+
+ <!-- OpenIddict 4.x: -->
+ <PackageReference Include="OpenIddict.AspNetCore" Version="4.0.0" />
+ <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="4.0.0" />
+</ItemGroup>
+
Note
Migrating to ASP.NET Core 7.0 is not required, as OpenIddict 4.0 is still natively compatible with ASP.NET Core 2.1 (.NET Framework-only), +ASP.NET Core 3.1 and ASP.NET Core 6.0. Moving to a newer .NET runtime or ASP.NET Core can be done separately for a simpler/decoupled upgrade:
+Web framework version | +.NET runtime version | +
---|---|
ASP.NET Core 2.1 | +.NET Framework 4.6.1 | +
ASP.NET Core 2.1 | +.NET Framework 4.7.2 | +
ASP.NET Core 2.1 | +.NET Framework 4.8 | +
+ | + |
ASP.NET Core 3.1 | +.NET Core 3.1 | +
+ | + |
ASP.NET Core 6.0 | +.NET 6.0 | +
ASP.NET Core 7.0 | +.NET 7.0 | +
+ | + |
Microsoft.Owin 4.2 | +.NET Framework 4.6.1 | +
Microsoft.Owin 4.2 | +.NET Framework 4.7.2 | +
Microsoft.Owin 4.2 | +.NET Framework 4.8 | +
Update your endpoint URIs
+OpenIddict 4.0 introduces a behavior change that affects how endpoint URIs are computed and resolved. For more information about this change, +read Breaking changes in OpenIddict 4.0 impacting how URIs are handled.
+In most cases, tweaking your code should be limited to removing the leading slashes in your endpoint paths to account for the new logic:
+services.AddOpenIddict()
+ .AddServer(options =>
+ {
+ // OpenIddict 3.x:
+ options.SetAuthorizationEndpointUris("/connect/authorize")
+ .SetDeviceEndpointUris("/connect/device")
+ .SetIntrospectionEndpointUris("/connect/introspect")
+ .SetLogoutEndpointUris("/connect/logout")
+ .SetTokenEndpointUris("/connect/token")
+ .SetUserinfoEndpointUris("/connect/userinfo")
+ .SetVerificationEndpointUris("/connect/verify");
+
+ // OpenIddict 4.x:
+ options.SetAuthorizationEndpointUris("connect/authorize")
+ .SetDeviceEndpointUris("connect/device")
+ .SetIntrospectionEndpointUris("connect/introspect")
+ .SetLogoutEndpointUris("connect/logout")
+ .SetTokenEndpointUris("connect/token")
+ .SetUserinfoEndpointUris("connect/userinfo")
+ .SetVerificationEndpointUris("connect/verify");
+ });
+
Remove calls to AddClaim(s)
that specify a list of destinations:
+As explained in OpenIddict 4.0 preview1 is out,
+the AddClaim(s)
extensions that accepted a destinations
parameter have been removed in 4.0.
Instead, developers are encouraged to use the new one-shot SetDestinations()
extension for ClaimsIdentity
+and ClaimsPrincipal
(that must be called after all the claims have been added to the identity/principal):
var identity = new ClaimsIdentity(
+ authenticationType: TokenValidationParameters.DefaultAuthenticationType,
+ nameType: Claims.Name,
+ roleType: Claims.Role);
+
+identity.SetClaim(Claims.Subject, await _userManager.GetUserIdAsync(user))
+ .SetClaim(Claims.Email, await _userManager.GetEmailAsync(user))
+ .SetClaim(Claims.Name, await _userManager.GetUserNameAsync(user))
+ .SetClaims(Claims.Role, (await _userManager.GetRolesAsync(user)).ToImmutableArray());
+
+identity.SetScopes(result.Principal.GetScopes());
+identity.SetResources(await _scopeManager.ListResourcesAsync(identity.GetScopes()).ToListAsync());
+
+identity.SetDestinations(static claim => claim.Type switch
+{
+ // Allow the "name" claim to be stored in both the access and identity tokens
+ // when the "profile" scope was granted (by calling principal.SetScopes(...)).
+ Claims.Name when claim.Subject.HasScope(Scopes.Profile)
+ => new[] { Destinations.AccessToken, Destinations.IdentityToken },
+
+ // Otherwise, only store the claim in the access tokens.
+ _ => new[] { Destinations.AccessToken }
+});
+
If applicable, update your OpenIddict MongoDB authorizations
+To match the casing used by the other properties, the name used in the BSON representation of the OpenIddictMongoDbAuthorization.CreationDate
+property was fixed to use camel case (i.e creation_name
instead of CreationDate
). To ensure the existing authorizations are correctly
+updated to use the new name, the following script can be used to update all the existing authorizations at once very efficiently:
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using MongoDB.Bson;
+using MongoDB.Driver;
+using OpenIddict.MongoDb;
+
+var services = new ServiceCollection();
+services.AddOpenIddict()
+ .AddCore()
+ .UseMongoDb()
+ .UseDatabase(new MongoClient("mongodb://localhost:27017").GetDatabase("openiddict"));
+
+await using var provider = services.BuildServiceProvider();
+var context = provider.GetRequiredService<IOpenIddictMongoDbContext>();
+var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictMongoDbOptions>>().CurrentValue;
+var database = await context.GetDatabaseAsync(CancellationToken.None);
+
+var authorizations = database.GetCollection<BsonDocument>(options.AuthorizationsCollectionName);
+await authorizations.UpdateManyAsync(
+ filter: Builders<BsonDocument>.Filter.Empty,
+ update: Builders<BsonDocument>.Update.Rename("CreationDate", "creation_date"));
+
If applicable, replace references to Portable.BouncyCastle
by BouncyCastle.Cryptography
+While previous versions of OpenIddict used the unofficial Portable.BouncyCastle
+package maintained by Claire Novotny (which was the best .NET Standard-compatible option at the time),
+OpenIddict 4.0 was updated to use the official package, BouncyCastle.Cryptography,
+that was released in November 2022 with complete .NET Standard 2.0 support.
If your application uses Portable.BouncyCastle
, it is strongly recommended to migrate to BouncyCastle.Cryptography
to avoid type conflicts.
If applicable, update your custom stores to use the updated signatures
+OpenIddict 4.x fixes the nullability annotations of IOpenIddictApplicationStore.GetAsync()
, IOpenIddictAuthorizationStore.GetAsync()
,
+IOpenIddictScopeStore.GetAsync()
and IOpenIddictTokenStore.GetAsync()
to return ValueTask<TResult?>
instead of ValueTask<TResult>
.
Developers who implemented these interfaces and enabled nullable references are invited to update the signature of the GetAsync()
methods:
// OpenIddict 3.x:
+ValueTask<TResult> GetAsync<TState, TResult>(
+ Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
+ TState state, CancellationToken cancellationToken);
+
+// OpenIddict 4.x:
+ValueTask<TResult?> GetAsync<TState, TResult>(
+ Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query,
+ TState state, CancellationToken cancellationToken);
+
While not required, it is recommended to also update implementations of IOpenIddictApplicationStore
to use the updated parameter names
+for FindByPostLogoutRedirectUriAsync()
, FindByRedirectUriAsync()
, SetPostLogoutRedirectUrisAsync()
and SetRedirectUrisAsync()
:
// OpenIddict 3.x:
+IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(string address, CancellationToken cancellationToken);
+IAsyncEnumerable<TApplication> FindByRedirectUriAsync(string address, CancellationToken cancellationToken);
+ValueTask SetPostLogoutRedirectUrisAsync(TApplication application, ImmutableArray<string> addresses, CancellationToken cancellationToken);
+ValueTask SetRedirectUrisAsync(TApplication application, ImmutableArray<string> addresses, CancellationToken cancellationToken);
+
+// OpenIddict 4.x:
+IAsyncEnumerable<TApplication> FindByPostLogoutRedirectUriAsync(string uri, CancellationToken cancellationToken);
+IAsyncEnumerable<TApplication> FindByRedirectUriAsync(string uri, CancellationToken cancellationToken);
+ValueTask SetPostLogoutRedirectUrisAsync(TApplication application, ImmutableArray<string> uris, CancellationToken cancellationToken);
+ValueTask SetRedirectUrisAsync(TApplication application, ImmutableArray<string> uris, CancellationToken cancellationToken);
+
Consider migrating to the new OpenIddict client (optional)
+OpenIddict 4.0 introduces a new client stack that is natively compatible with all supported versions of ASP.NET Core (2.1
+on .NET Framework, 3.1, 6.0 and 7.0) and Microsoft.Owin
4.2 (which means it can also be used on ASP.NET 4.6.1 and higher).
For more information, read OpenIddict 4.0 general availability.
+