Closed jennyf19 closed 1 year ago
Microsoft.IdentityModel.Tokens.Jwt
is the old generation. Notable types areJwtSecurityToken
andJwtSecurityTokenHandler
. This is the assembly currently used by ASP.NET Core.
System.IdentityModel.Tokens.Jwt
you mean?
Yes! Great catch! Have fixed, thanks for pointing that out @cakescience
API Review Notes:
SecurityTokenValidators
is the name of the existing IList<ISecurityTokenValidator>
. This will now be disabled by default.
IList
throw if it is modified for clearer errors?JwtBearerEvents
or other events, but some people do downcast TokenValidatedContext.SecurityToken
to JwtSecurityToken
while it will now be a JsonWebToken
which does not implement, e.g. https://github.com/AzureAD/microsoft-identity-web/blob/07f896d427f52552c0fa5b18a463f1dc0c9dadce/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilder.cs#L102. It will now be
JwtSecurityToken
to JsonWebToken
.UseTokenHandlers
default to true?
UseTokenHandlers
via named options even if you didn't add the auth hander directly.true
manually, neither code path will be trimmed.JwtSecurityToken
logic.UseSecurityTokenValidators
? Yes.MapInboundClaimsTokenHandler
? Can we continue to use MapInboundClaims
and have it map to both? It's intended to do the same thing.
API Approved!
namespace Microsoft.AspNetCore.Authentication.JwtBearer;
public class JwtBearerOptions : AuthenticationSchemeOptions
{
+ [Obsolete("SecurityTokenValidators is no longer used by default. Use TokenHandlers instead. To continue using SecurityTokenValidators, set UseSecurityTokenValidators to true.")]
public IList<ISecurityTokenValidator> SecurityTokenValidators { get; }
+ public IList<TokenHandler> TokenHandlers { get; }
+ public bool UseSecurityTokenValidators { get; set; }
}
namespace Microsoft.AspNetCore.Authentication.WsFederation;
public class WsFederationOptions : RemoteAuthenticationOptions
{
+ [Obsolete("SecurityTokenValidators is no longer used by default. Use TokenHandlers instead. To continue using SecurityTokenValidators, set UseSecurityTokenValidators to true.")]
public IList<ISecurityTokenValidator> SecurityTokenValidators { get; }
+ public IList<TokenHandler> TokenHandlers { get; }
+ public bool UseSecurityTokenValidators { get; set; }
}
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect;
public class OpenIdConnectOptions : RemoteAuthenticationOptions
{
+ [Obsolete("SecurityTokenValidator is no longer used by default. Use TokenHandler instead. To continue using SecurityTokenValidators, set UseSecurityTokenValidator to true.")]
public ISecurityTokenValidator SecurityTokenValidator { get; set; }
+ public TokenHandler TokenHandler { get; set; }
+ public bool UseSecurityTokenValidator { get; set; }
}
~This is not for ASP.NET Core, but in System.IdentityModel.Token.Jwt we'd like to see an explicit conversion.~ Edit: This doesn't work because the declared type is just SecurityToken not JwtSecurityToken.
namespace System.IdentityModel.Tokens.Jwt;
public class JwtSecurityToken : SecurityToken
{
// Edit: This was suggested as an addition earlier. I'm now putting a '-' instead of a '+' to make it extra clear not to add it.
- public static explicit operator JsonWebToken(JwtSecurityToken token);
}
Background and Motivation
Improvements in
JsonWebToken
andJsonWebTokenHandler
have been made inMicrosoft.IdentityModel
, which include a 30% performance improvement overJwtSecurityToken
which is currently used in ASP.NET today. In later versions of Microsoft.IdentityModel 7.x (before .NET8 RC1), we will enable AOT support by having fully trimmable assemblies inMicrosoft.IdentityModel
and remove the dependency of Newtonsoft, enabling a smaller dll for AOT.Microsoft.IdentityModel
offers two generations of JSON web token (JWT) handling, which are in two assemblies:System.IdentityModel.Tokens.Jwt
is the old generation. Notable types areJwtSecurityToken
andJwtSecurityTokenHandler
. This is the assembly currently used by ASP.NET Core.Microsoft.IdentityModel.Tokens.JsonWebToken
is the next generation. It offersJsonWebToken
andJsonWebTokenHandler
with:Improved performance (30%)
Better resilience: IdentityModel will fetch and maintain the OIDC metadata and uses its last known good state (repair item from March 2020 outage)
Defense in depth: IdentityModel provides additional AAD key issuer validation protection
Support for async token validation, returning a
TokenValidationResult
rather than throwingMicrosoft.IdentityModel
also has two abstractions for Token Handlers:ISecurityTokenValidator
is the old generation.TokenHandler
(abstract class) is the next generation and offers asynchronous token validation.The following assemblies have a dependency on
JwtSecurityToken
, orJwtSecurityTokenHandler
:Microsoft.AspNetCore.Authentication.JwtBearer
,Microsoft.AspNetCore.Authentication.OpenIdConnect
,Microsoft.AspNetCore.Authentication.WsFederation
,Microsoft.AspNetCore.Authentication
Proposed API
We introduce a new boolean,
UseTokenHandlers
, in the JwtBearer and WsFederation options to enable developers to decide whether the access token validation will be done with the newTokenHandlers
(more performant, resilient and async) or with the legacySecurityTokenValidators
. We also expose the list ofTokenHandlers
used to validate the token. Developers can decide to add their ownTokenHandlers
(token type) for each protocol (JwtBearer/WsFed). By defaultJwtBearerOptions.TokenHandlers
contains an instance of theJsonWebTokenHandler
andWsFederationOptions.TokenHandlers
contains handlers for SAML1, SAML2, andJsonWebTokenHandler
.PR for reference
Additions in
JwtBearer
:Additions in
WsFederation
:Additions in
OpenIdConnect
: We introduce a new boolean,UseTokenHandler
, in the OpenIdConnect options to enable developers to decide whether the ID token validation will be done with the newTokenHandler
(more performant, resilient and async) or with the legacySecurityTokenValidator
.PR for reference
Usage Examples
By default, ASP.NET Core in .NET 8 uses the new TokenHandler. If a developer wants to use the legacy validators, they can set
UseTokenHandlers = false
.If a developer wants to have their own TokenHandler, they can add it to the list of TokenHandlers:
Alternative Designs
Alternative designs were discussed with @Tratcher, @eerhardt, @halter73 . We went with Option A_1, but the alternatives discussed were:
Option A_1: Have the same assemblies as today with a dual dependency on System.IdentityModel.Tokens.Jwt and Microsoft.IdentityModel.Tokens.JsonWebToken, and offer both interfaces (Jwt for compatibility, whereas the processing is done with JsonWebToken). In practice, note that the Jwt Wilson assembly already depends on the JsonWebToken Wilson assembly, so there would not be any additional dependencies than today. Additionally, to leverage the new generation of Wilson assemblies without breaking changes, both ISecurityTokenValidator and TokenHandler members would have to be in ASP.NET core’s surface area. Validation would need to be done on the options such that when using a new generation of Jwt classes, the new generation of the TokenHandlers would also need be used.
Option A_2: Duplicate the current ASP.NET Core assemblies, and have a new generation (let’s name them Microsoft.AspNetCore.Authentication.JwtBearer2. Microsoft.AspNetCore.Authentication.OpenIdConnect2, Microsoft.AspNetCore.Authentication.WsFederation2, Microsoft.AspNetCore.Authentication2 for now, until we have a better name), and have these new generation depend only on JsonWebToken, and only expose these concepts. Letting the old generation leverage only Jwt. Additionally, these new assemblies would only rely on TokenHandler and drop support for ISecurityTokenValidator In practice, we could, for this Option A2, use the same codebase, but add the files of the old projects as links in the new project, with conditional projects)
Option A_3: Breaking changes in ASP.NET to rely only on the Microsoft.IdentityModel.Tokens.JsonWebToken assembly for Jwts and only TokenHandler for token handler abstractions. In practice, these breaking changes should only affect users that leverage the extensibility features. We need to understand how large of a population this would affect.
Also gathering customer feedback in the GitHub discussion in Microsoft.IdentityModel repo and the two above mentioned PRs.
Risks
When setting
UseTokenHandlers
orUseTokenHandler
totrue
, the SecurityToken passed in the context of the TokenValidated event needs to be downcast to JsonWebToken instead of JwtSecurityToken for users who were already doing this, which is not a common scenario, but for more advanced users. Mitigation for the risk is to have an implicit operator.Initial feedback on 7.0.0-preview of Microsoft.IdentityModel from @kevinchalet: "FYI, I tested the 7.0.0-preview packages with OpenIddict and haven't seen any particular regression. Good job"