+Migrate to OpenIddict RC3
+
+What's new in OpenIddict RC3?
+The announcement listing the changes introduced in this milestone can be found here.
+Update your packages references
+For that, simply update your .csproj
file to point to the newest OpenIddict packages:
+ASP.NET Core 1.x
+<ItemGroup>
+ <PackageReference Include="OpenIddict" Version="1.0.0-rc3-final" />
+ <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="1.0.0-rc3-final" />
+</ItemGroup>
+
ASP.NET Core 2.x
+<ItemGroup>
+ <PackageReference Include="OpenIddict" Version="2.0.0-rc3-final" />
+ <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="2.0.0-rc3-final" />
+</ItemGroup>
+
Tip
Note: if you have an explicit reference to AspNet.Security.OAuth.Validation
or OpenIddict.Mvc
,
+you can safely remove these dependencies: they are now transitively referenced by the OpenIddict
metapackage.
+
+Important
Note: if your application references OpenIddict.Models
or OpenIddict.Stores
, you MUST remove them as these packages are no longer used in RC3.
+
+Use the new OpenIddict services registration APIs
+To offer a better user experience, the registrations APIs exposed by OpenIddict have been reworked. Updating your code should be quite straightforward:
+// In OpenIddict RC2, all the options used to be grouped.
+services.AddOpenIddict(options =>
+{
+ options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
+
+ options.AddMvcBinders();
+
+ options.EnableAuthorizationEndpoint("/connect/authorize")
+ .EnableLogoutEndpoint("/connect/logout")
+ .EnableTokenEndpoint("/connect/token")
+ .EnableUserinfoEndpoint("/api/userinfo");
+
+ options.AllowAuthorizationCodeFlow()
+ .AllowPasswordFlow()
+ .AllowRefreshTokenFlow();
+
+ options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
+ OpenIdConnectConstants.Scopes.Profile,
+ OpenIddictConstants.Scopes.Roles);
+
+ options.RequireClientIdentification();
+
+ options.EnableRequestCaching();
+
+ options.EnableScopeValidation();
+
+ options.DisableHttpsRequirement();
+});
+
// In OpenIddict RC3, the options are now split into 3 categories:
+// the core services, the server services and the validation services.
+services.AddOpenIddict()
+ .AddCore(options =>
+ {
+ // AddEntityFrameworkCoreStores() is now UseEntityFrameworkCore().
+ options.UseEntityFrameworkCore()
+ .UseDbContext<ApplicationDbContext>();
+ })
+
+ .AddServer(options =>
+ {
+ // AddMvcBinders() is now UseMvc().
+ options.UseMvc();
+
+ options.EnableAuthorizationEndpoint("/connect/authorize")
+ .EnableLogoutEndpoint("/connect/logout")
+ .EnableTokenEndpoint("/connect/token")
+ .EnableUserinfoEndpoint("/api/userinfo");
+
+ options.AllowAuthorizationCodeFlow()
+ .AllowPasswordFlow()
+ .AllowRefreshTokenFlow();
+
+ options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
+ OpenIdConnectConstants.Scopes.Profile,
+ OpenIddictConstants.Scopes.Roles);
+
+ // This API was removed as client identification is now
+ // required by default. You can remove or comment this line.
+ //
+ // options.RequireClientIdentification();
+
+ options.EnableRequestCaching();
+
+ // This API was removed as scope validation is now enforced
+ // by default. You can safely remove or comment this line.
+ //
+ // options.EnableScopeValidation();
+
+ options.DisableHttpsRequirement();
+ });
+
Move to the OpenIddict validation handler (optional)
+While not required, moving to the new validation handler is recommended:
+// Replace...
+services.AddAuthentication()
+ .AddOAuthValidation();
+
+// ... by:
+services.AddOpenIddict()
+ .AddValidation();
+
Tip
Note: the OpenIddict validation handler lives in the OpenIddict.Validation
package, which is referenced by the OpenIddict
metapackage.
+You don't have to explicitly add a new PackageReference
in your .csproj
file to be able to use it.
+
+If necessary, create new application entries
+OpenIddict now rejects unauthenticated token/revocation requests by default.
+If, after migrating to RC3, you see errors similar to this one:
+invalid_request : The mandatory 'client_id' parameter is missing.
+
+Add an application entry for the client application and send the corresponding client_id
as part of the token request:
+var descriptor = new OpenIddictApplicationDescriptor
+{
+ ClientId = "postman",
+ DisplayName = "Postman",
+ Permissions =
+ {
+ OpenIddictConstants.Permissions.Endpoints.Token,
+ OpenIddictConstants.Permissions.GrantTypes.Password,
+ OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
+ OpenIddictConstants.Permissions.Scopes.Email,
+ OpenIddictConstants.Permissions.Scopes.Profile,
+ OpenIddictConstants.Permissions.Scopes.Roles
+ }
+};
+
+await _applicationManager.CreateAsync(descriptor);
+
If you prefer accepting anonymous clients, use options.AcceptAnonymousClients()
:
+services.AddOpenIddict()
+ .AddServer(options =>
+ {
+ options.AcceptAnonymousClients();
+ });
+
If necessary, register the scopes used by your clients
+Starting with RC3, OpenIddict will reject unrecognized scopes by default.
+If, after migrating to RC3, you see errors similar to this one:
+invalid_scope : The specified 'scope' parameter is not valid.
+
+Simply add the scopes you want to use to the list of registered scopes:
+services.AddOpenIddict()
+
+ // Register the OpenIddict server handler.
+ .AddServer(options =>
+ {
+ options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
+ OpenIdConnectConstants.Scopes.Profile,
+ OpenIddictConstants.Scopes.Roles);
+ });
+
If you prefer disabling scope validation, use options.DisableScopeValidation()
:
+services.AddOpenIddict()
+ .AddServer(options =>
+ {
+ options.DisableScopeValidation();
+ });
+
If necessary, adjust the permissions granted to your clients
+Starting with RC3, permissions are no longer optional nor implicit:
+if you don't explicitly grant an application the necessary permissions, it will be blocked by OpenIddict.
+To attach permissions to an application, use OpenIddictApplicationManager
:
+var descriptor = new OpenIddictApplicationDescriptor
+{
+ ClientId = "mvc",
+ ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
+ DisplayName = "MVC client application",
+ PostLogoutRedirectUris = { new Uri("http://localhost:53507/signout-callback-oidc") },
+ RedirectUris = { new Uri("http://localhost:53507/signin-oidc") },
+ Permissions =
+ {
+ OpenIddictConstants.Permissions.Endpoints.Authorization,
+ OpenIddictConstants.Permissions.Endpoints.Logout,
+ OpenIddictConstants.Permissions.Endpoints.Token,
+ OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
+ OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
+ OpenIddictConstants.Permissions.Scopes.Email,
+ OpenIddictConstants.Permissions.Scopes.Profile,
+ OpenIddictConstants.Permissions.Scopes.Roles
+ }
+};
+
+await _applicationManager.CreateAsync(descriptor);
+
If you don't care about permissions (e.g because you don't have third-party clients), you can instead disable them:
+services.AddOpenIddict()
+
+ // Register the OpenIddict server handler.
+ .AddServer(options =>
+ {
+ options.IgnoreEndpointPermissions()
+ .IgnoreGrantTypePermissions()
+ .IgnoreScopePermissions();
+ });
+
+Migrate to OpenIddict RC2
+What's new in OpenIddict RC2?
+The full list of changes can be found here. It includes bug fixes (including a bug fix in the refresh token handling)
+and new features like application permissions, that allow limiting the OpenID Connect features (endpoints and flows) an application is able to use.
+Migrating to OpenIddict RC2 (1.0.0-rc2-final
and 2.0.0-rc2-final
) requires making changes in your database: existing properties have been reworked
+(e.g to work around a MySQL limitation) and new ones have been added to support the new features.
+This procedure is quite easy and only requires a few minutes.
+Note: this guide assumes your application uses the OpenIddict Entity Framework Core 2.x stores. If you use a custom store, changes will have to be made manually.
+A list of added/updated/renamed columns is available at the end of this guide.
+
+Ensure migrations are correctly enabled for your project
+Before migrating to OpenIddict RC2, make sure migrations are already enabled for your application. If you have a Migrations
+folder in your application root folder and an __EFMigrationsHistory
table in your database, you're good to go.
+If you don't have these Entity Framework Core artifacts, migrations are likely not enabled. To fix that, add the following entries in your .csproj
:
+<ItemGroup>
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Design"
+ Version="2.0.0" PrivateAssets="All" />
+</ItemGroup>
+
+<ItemGroup>
+ <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet"
+ Version="2.0.0" />
+</ItemGroup>
+
Then, open a new command line and add an initial migration using dotnet ef migrations add InitialMigration
(but don't apply it!).
+Update your packages references
+For that, simply update your .csproj
file to point to the newest OpenIddict packages:
+ASP.NET Core 1.x
+<ItemGroup>
+ <PackageReference Include="OpenIddict" Version="1.0.0-rc2-final" />
+ <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="1.0.0-rc2-final" />
+ <PackageReference Include="OpenIddict.Mvc" Version="1.0.0-rc2-final" />
+</ItemGroup>
+
ASP.NET Core 2.x
+<ItemGroup>
+ <PackageReference Include="OpenIddict" Version="2.0.0-rc2-final" />
+ <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="2.0.0-rc2-final" />
+ <PackageReference Include="OpenIddict.Mvc" Version="2.0.0-rc2-final" />
+</ItemGroup>
+
Add a new migration
+
+- First, open a new command line and run
dotnet ef migrations add MigrateToOpenIddictRc2
.
+- If you created an initial migration at step 1, remove it from the
Migrations
folder.
+- Apply the
MigrateToOpenIddictRc2
migration using dotnet ef database update MigrateToOpenIddictRc2
.
+
+
+For that, add the following snippet to your Startup
class:
+private async Task UpdateOpenIddictTablesAsync(IServiceProvider services)
+{
+ using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
+ {
+ // Change ApplicationDbContext to match your context name if you've changed it.
+ var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
+ await context.Database.EnsureCreatedAsync();
+
+ // If you use a different entity type or a custom key,
+ // change this line (e.g OpenIddictApplication<long>).
+ foreach (var application in context.Set<OpenIddictApplication>())
+ {
+ // Convert the space-separated PostLogoutRedirectUris property to JSON.
+ if (!string.IsNullOrEmpty(application.PostLogoutRedirectUris) &&
+ application.PostLogoutRedirectUris[0] != '[')
+ {
+ var addresses = application.PostLogoutRedirectUris.Split(
+ new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+ application.PostLogoutRedirectUris =
+ new JArray(addresses).ToString(Formatting.None);
+ }
+
+ // Convert the space-separated RedirectUris property to JSON.
+ if (!string.IsNullOrEmpty(application.RedirectUris) &&
+ application.RedirectUris[0] != '[')
+ {
+ var addresses = application.RedirectUris.Split(
+ new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+ application.RedirectUris = new JArray(addresses).ToString(Formatting.None);
+ }
+ }
+
+ // If you use a different entity type or a custom key,
+ // change this line (e.g OpenIddictAuthorization<long>).
+ foreach (var authorization in context.Set<OpenIddictAuthorization>())
+ {
+ // Convert the space-separated Scopes property to JSON.
+ if (!string.IsNullOrEmpty(authorization.Scopes) && authorization.Scopes[0] != '[')
+ {
+ var scopes = authorization.Scopes.Split(
+ new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
+
+ authorization.Scopes = new JArray(scopes).ToString(Formatting.None);
+ }
+ }
+
+ await context.SaveChangesAsync();
+ }
+}
+
Then, at the end of the public void Configure(IApplicationBuilder app)
method, add the following line:
+public void Configure(IApplicationBuilder app)
+{
+ app.UseDeveloperExceptionPage();
+
+ app.UseStaticFiles();
+
+ app.UseStatusCodePagesWithReExecute("/error");
+
+ app.UseAuthentication();
+
+ app.UseMvcWithDefaultRoute();
+
+ // Run the migration script synchronously.
+ UpdateOpenIddictTablesAsync(app.ApplicationServices).GetAwaiter().GetResult();
+}
+
Run your application. Once it's correctly started, stop it and remove the migration script.
+If your authorization server uses introspection, make sure resources are set in the authentication ticket
+Setting an explicit list of resources is now required to allow client applications to introspect a token.
+For that, call ticket.SetResources()
with the list of the client identifiers allowed to validate the token. E.g:
+var ticket = new AuthenticationTicket(
+ new ClaimsPrincipal(identity),
+ new AuthenticationProperties(),
+ OpenIdConnectServerDefaults.AuthenticationScheme);
+
+ticket.SetResources("tracking_api", "marketing_api");
+
Optionally, update your code to grant applications the minimum required permissions
+Starting with RC2, OpenIddict includes an optional feature codenamed "app permissions" that allows
+controlling and limiting the OAuth2/OpenID Connect features a client application is able to use.
+To learn more about this feature, read the Application permissions documentation.
+List of changes (for applications using custom stores)
+Renamed properties
+
+
+
+Table |
+Old column name |
+New column name |
+Observations |
+
+
+
+
+OpenIddictApplications |
+Timestamp |
+ConcurrencyToken |
+The column type was changed to nvarchar to work around a MySQL limitation. |
+
+
+OpenIddictAuthorizations |
+Timestamp |
+ConcurrencyToken |
+The column type was changed to nvarchar to work around a MySQL limitation. |
+
+
+OpenIddictScopes |
+Timestamp |
+ConcurrencyToken |
+The column type was changed to nvarchar to work around a MySQL limitation. |
+
+
+OpenIddictTokens |
+Timestamp |
+ConcurrencyToken |
+The column type was changed to nvarchar to work around a MySQL limitation. |
+
+
+OpenIddictTokens |
+Ciphertext |
+Payload |
+ |
+
+
+OpenIddictTokens |
+Hash |
+ReferenceId |
+ |
+
+
+
+Updated properties
+
+
+
+Table |
+Column name |
+Observations |
+
+
+
+
+OpenIddictApplications |
+PostLogoutRedirectUris |
+Values are now formatted as JSON arrays instead of space-separated strings. |
+
+
+OpenIddictApplications |
+RedirectUris |
+Values are now formatted as JSON arrays instead of space-separated strings. |
+
+
+OpenIddictAuthorizations |
+Scopes |
+Values are now formatted as JSON arrays instead of space-separated strings. |
+
+
+
+Added properties
+
+
+
+Table |
+Column name |
+Type |
+Nullable |
+
+
+
+
+OpenIddictApplications |
+ConsentType |
+nvarchar(max) |
+Yes |
+
+
+OpenIddictApplications |
+Properties |
+nvarchar(max) |
+Yes |
+
+
+OpenIddictApplications |
+Permissions |
+nvarchar(max) |
+Yes |
+
+
+OpenIddictAuthorizations |
+Properties |
+nvarchar(max) |
+Yes |
+
+
+OpenIddictScopes |
+DisplayName |
+nvarchar(max) |
+Yes |
+
+
+OpenIddictScopes |
+Properties |
+nvarchar(max) |
+Yes |
+
+
+OpenIddictScopes |
+Resources |
+nvarchar(max) |
+Yes |
+
+
+OpenIddictTokens |
+Properties |
+nvarchar(max) |
+Yes |
+
+
+
+