7.0.0-preview.2
Pre-releaseThis release introduces the following changes:
-
All the OpenIddict assemblies have been marked as trimming and Native AOT-compatible (only on .NET 9.0 and higher). For that, several changes had to be made to the OpenIddict core stack:
-
The store resolver interfaces (
IOpenIddict*StoreResolver
) and all their implementations have been removed and the managers have been updated to now directly take anIOpenIddict*Store<T>
argument instead of anIOpenIddict*StoreResolver
. -
All the
OpenIddictCoreOptions.Default*Type
options (e.gDefaultApplicationType
) have been removed and the untyped managers (IOpenIddict*Manager
) no longer use options to determine the actual entity type at runtime. Instead, each store integration is now responsible for replacing theIOpenIddict*Manager
services with a service descriptor pointing to the genericOpenIddict*Manager<T>
implementation with the correctT
argument: by default, the default entity types provided by the store are used, but the managers can be re-registered with a different type when the user decides to use different models (e.g viaoptions.UseEntityFrameworkCore().ReplaceDefaultModels<...>()
). -
All the managers/store/store resolvers registration APIs offered by
OpenIddictCoreBuilder
have been removed: while they were very powerful and easy-to-use (e.g theReplace*Manager
methods supported both open and closed generic types and were able to determine the entity type from the base type definition), they weren't AOT-compatible. -
New AOT-friendly
Replace*Store()
andReplace*Manager()
APIs have been introduced inOpenIddictCoreBuilder
. The newReplace*Manager()
APIs have two overloads that can be used depending on whether you need to register a closed or open generic type:options.ReplaceApplicationManager< /* TApplication: */ OpenIddictEntityFrameworkCoreApplication, /* TManager: */ CustomApplicationManager<OpenIddictEntityFrameworkCoreApplication>>();
options.ReplaceApplicationManager(typeof(CustomApplicationManager<>));
-
While they are currently not functional on Native AOT due to EF Core not supporting interpreted LINQ expressions yet, the EF Core stores package has been updated to be ready for AOT: as part of this change, the signature of all the stores has been updated to remove the
TContext
generic argument from the definition. Similarly, the MongoDB C# driver isn't AOT (or even trimming) compatible yet, but the stores have been updated to ensure they only use statically-analyzable patterns. -
A new
IOpenIddictEntityFrameworkCoreContext
interface containing a singleValueTask<DbContext> GetDbContextAsync(CancellationToken cancellationToken)
method (similar to what's currently used in the MongoDB integration) has been introduced to allow each to resolve theDbContext
to use. A default implementation namedOpenIddictEntityFrameworkCoreContext<TContext>
is used by theOpenIddictEntityFrameworkCoreBuilder.UseDbContext<TContext>()
API to resolve theTContext
type specified by the user. -
The
OpenIddictEntityFrameworkCoreBuilder.ReplaceDefaultEntities<...>
API has been preserved - including the overload accepting a singleTKey
parameter but no longer use options internally. Instead, they re-register the untypedIOpenIddict*Manager
to point to the correctOpenIddict*Manager<T>
instances depending on the generic types set by the user.
-
-
For consistency with the Entity Framework Core stores, the
OpenIddictEntityFrameworkBuilder.UseDbContext<TContext>()
API will no longer automatically register theDbContext
type in the DI container. -
The authorization endpoint now uses
Cache-Control: no-store
instead ofCache-Control: no-cache
when generating HTML auto-post form responses (thanks @matthid! ❤️) -
OpenIddict 7.0 preview 2 no longer allows dynamically overriding the
prompt
value when using OAuth 2.0 Pushed Authorization Requests.
Important
To prevent login endpoint -> authorization endpoint loops, developers are invited to update their authorization endpoint MVC action to use TempData
to store a flag indicating whether the user has already been offered to re-authenticate and avoid triggering a new authentication challenge in that case. For instance:
// Try to retrieve the user principal stored in the authentication cookie and redirect
// the user agent to the login page (or to an external provider) in the following cases:
//
// - If the user principal can't be extracted or the cookie is too old.
// - If prompt=login was specified by the client application.
// - If max_age=0 was specified by the client application (max_age=0 is equivalent to prompt=login).
// - If a max_age parameter was provided and the authentication cookie is not considered "fresh" enough.
//
// For scenarios where the default authentication handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
var result = await HttpContext.AuthenticateAsync();
if (result is not { Succeeded: true } ||
((request.HasPromptValue(PromptValues.Login) || request.MaxAge is 0 ||
(request.MaxAge != null && result.Properties?.IssuedUtc != null &&
TimeProvider.System.GetUtcNow() - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value))) &&
TempData["IgnoreAuthenticationChallenge"] is null or false))
{
// If the client application requested promptless authentication,
// return an error indicating that the user is not logged in.
if (request.HasPromptValue(PromptValues.None))
{
return Forbid(
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in."
}));
}
// To avoid endless login endpoint -> authorization endpoint redirects, a special temp data entry is
// used to skip the challenge if the user agent has already been redirected to the login endpoint.
//
// Note: this flag doesn't guarantee that the user has accepted to re-authenticate. If such a guarantee
// is needed, the existing authentication cookie MUST be deleted AND revoked (e.g using ASP.NET Core
// Identity's security stamp feature with an extremely short revalidation time span) before triggering
// a challenge to redirect the user agent to the login endpoint.
TempData["IgnoreAuthenticationChallenge"] = true;
// For scenarios where the default challenge handler configured in the ASP.NET Core
// authentication options shouldn't be used, a specific scheme can be specified here.
return Challenge(new AuthenticationProperties
{
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(
Request.HasFormContentType ? Request.Form : Request.Query)
});
}