Migrate to OpenIddict 3.0
What's new?
The announcement listing the changes introduced in this milestone can be found here.
IMPORTANT
Migrating to OpenIddict 3.0 requires making changes to your database: existing properties have been reworked and new ones have been added to support the new features.
Update your packages references
For that, update your .csproj
file to reference the OpenIddict.AspNetCore
3.x metapackage:
<ItemGroup>
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
</ItemGroup>
Ensure your application doesn't reference legacy/unsupported packages
As part of the AspNet.Security.OpenIdConnect.Server/OpenIddict merge, the ASOS packages and 2 OpenIddict packages have been marked as legacy and are no longer supported. Make sure your application (or intermediate libraries) don't reference any of these packages:
Package name |
---|
AspNet.Security.OpenIdConnect.Extensions |
AspNet.Security.OpenIdConnect.Primitives |
AspNet.Security.OpenIdConnect.Server |
Owin.Security.OpenIdConnect.Extensions |
Owin.Security.OpenIdConnect.Server |
AspNet.Security.OAuth.Introspection |
AspNet.Security.OAuth.Validation |
Owin.Security.OAuth.Introspection |
Owin.Security.OAuth.Validation |
OpenIddict.Models |
OpenIddict.Mvc |
IMPORTANT
If your application references the OpenIdConnectConstants
class, update it to use OpenIddictConstants
instead.
Update the references to the Entity Framework Core/Entity Framework 6/MongoDB models
If your application references the OpenIddictApplication
, OpenIddictAuthorization
, OpenIddictScope
or OpenIddictToken
models, update these reference to use their new names:
Old name | New name (Entity Framework Core) | New name (Entity Framework 6) | New name (MongoDB) |
---|---|---|---|
OpenIddictApplication | OpenIddictEntityFrameworkCoreApplication | OpenIddictEntityFrameworkApplication | OpenIddictMongoDbApplication |
OpenIddictAuthorization | OpenIddictEntityFrameworkCoreAuthorization | OpenIddictEntityFrameworkAuthorization | OpenIddictMongoDbAuthorization |
OpenIddictScope | OpenIddictEntityFrameworkCoreScope | OpenIddictEntityFrameworkScope | OpenIddictMongoDbScope |
OpenIddictToken | OpenIddictEntityFrameworkCoreToken | OpenIddictEntityFrameworkToken | OpenIddictMongoDbToken |
Enable ASP.NET Core integration in the server and validation options
With the base server and validation stacks being decoupled from ASP.NET Core, you now have to explicitly register the ASP.NET Core host in the server/validation options:
services.AddOpenIddict()
.AddServer(options =>
{
options.UseAspNetCore();
})
.AddValidation(options =>
{
options.UseAspNetCore();
});
Enable the authorization, logout and token endpoints pass-through mode
Unless you're using OpenIddict's events model to handle authorization, logout and token requests, you'll need to enable the pass-through mode for these endpoints, so that requests can reach your authorization controller as in the previous versions:
services.AddOpenIddict()
.AddServer(options =>
{
options.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableTokenEndpointPassthrough();
});
Enable ASP.NET Core Data Protection support to ensure existing tokens can still be validated
For that, call options.UseDataProtection()
in both the server and validation options:
services.AddOpenIddict()
.AddServer(options =>
{
options.UseDataProtection();
})
.AddValidation(options =>
{
options.UseDataProtection();
});
Use the new request caching APIs, if applicable
In 3.0, the OpenIddictServerBuilder.EnableRequestCaching()
API - that enabled request caching for both authorization and logout request - was replaced by 2 separate methods. If your application depends on request caching, don't forget to enable it when migrating to 3.0:
services.AddOpenIddict()
.AddServer(options =>
{
options.UseAspNetCore()
.EnableAuthorizationRequestCaching()
.EnableLogoutRequestCaching();
});
Replace JSON.NET by System.Text.Json
If you use JSON.NET to serialize or deserialize OpenIdConnectMessage
, OpenIdConnectRequest
or OpenIdConnectResponse
instances, consider moving to System.Text.Json
when migrating to OpenIddict 3.0, as 3.0 no longer includes a built-in JSON.NET JsonConverter
for their equivalent in 3.0 (i.e OpenIddictMessage
, OpenIddictRequest
and OpenIddictResponse
).
In most cases, this should be as simple as replacing JsonConvert.SerializeObject()
/JsonConvert.DeserializeObject()
by their System.Text.Json
equivalent: JsonSerializer.Serialize()
/JsonSerializer.Deserialize()
.
Replace calls to the AuthenticationTicket
extensions by their new ClaimsPrincipal
equivalent:
OpenIddict 3.0 no longer uses the AuthenticationTicket
type provided by ASP.NET Core. Instead, everything is now stored in the ClaimsPrincipal
instance. If you have calls like ticket.SetScopes()
or ticket.SetResources()
, use their new equivalents (e.g principal.SetScopes()
or principal.SetResources()
).
Use the new authentication schemes
In 3.0, the constants used as the ASP.NET Core authentication schemes have changed:
Old constant name | New constant name (ASP.NET Core host) |
---|---|
OpenIddictServerDefaults.AuthenticationScheme | OpenIddictServerAspNetCoreDefaults.AuthenticationScheme |
OpenIddictValidationDefaults.AuthenticationScheme | OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme |
OAuthValidationDefaults.AuthenticationScheme | OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme |
NOTE
In 3.0, the OpenIddict server ASP.NET Core handler supports authenticating userinfo requests. As such, if you use the pass-through mode to handle userinfo requests in your own userinfo MVC action, consider using OpenIddictServerAspNetCoreDefaults.AuthenticationScheme
instead of OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme
for your userinfo endpoint to avoid validating access tokens twice.
Update your application to work with the new scope
format
In OpenIddict 3.0, the format of the scope
claim used in JWT tokens has changed from a JSON array to a single space-separated claim to match the JWT access token specification. To ensure your authorization policies still work after migrating, consider using the principal.HasScope()
extension to determine whether a scope has been granted:
services.AddAuthorization(options =>
{
options.AddPolicy("MyPolicy", builder =>
{
builder.RequireAuthenticatedUser();
builder.RequireAssertion(context => context.User.HasScope("api1"));
});
});
Alternatively, you can use the check the presence of the private OpenIddict oi_scp
claims that use the same format as in 2.x (i.e one claim per scope value):
services.AddAuthorization(options =>
{
options.AddPolicy("MyPolicy", builder =>
{
builder.RequireAuthenticatedUser();
builder.RequireClaim(Claims.Private.Scope, "api1");
});
});
CAUTION
These 2 options only work with the OpenIddict validation handler as the oi_scp
claims are not populated by the JWT bearer handler developped by Microsoft. If you can't migrate to the OpenIddict validation handler, consider splitting the standard scope
claim manually to determine whether it contains a specific value.
Add and apply migrations, if necessary
If your application uses Entity Framework Core or Entity Framework 6, add a migration to react to the schema changes listed below and apply it.
Updated properties
Table | Column name | Observations |
---|---|---|
OpenIddictAuthorizations | Subject | The column is now nullable to support the device authorization flow. |
OpenIddictTokens | CreationDate | For broader database support, this column is a now a DateTime instance. |
OpenIddictTokens | ExpirationDate | For broader database support, this column is a now a DateTime instance. |
OpenIddictTokens | Subject | The column is now nullable to support the device authorization flow. |
Added properties
Table | Column name | Type | Nullable |
---|---|---|---|
OpenIddictApplications | DisplayNames | string | Yes |
OpenIddictApplications | Requirements | string | Yes |
OpenIddictAuthorizations | CreationDate | DateTime | Yes |
OpenIddictScopes | Descriptions | string | Yes |
OpenIddictScopes | DisplayNames | string | Yes |
OpenIddictTokens | RedemptionDate | DateTime | Yes |
If necessary, enable hybrid flow support in the server options
In 2.0, the hybrid flow was automatically enabled if both the authorization code and implicit flows were enabled. In 3.0, this is no longer true and the hybrid flow MUST be explicitly opted in. If you use the hybrid flow, make sure your application calls the options.AllowHybridFlow()
method:
services.AddOpenIddict()
.AddServer(options =>
{
options.AllowHybridFlow();
});
Update your applications to grant them the appropriate response type permissions
New response type permissions - enforced by default - have been introduced in 3.0.
NOTE
If you have many applications to migrate, you can use this script to infer appropriate response type permissions using the already granted grant types.