Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Net8 uses the new JwtSecurityTokenHandler() WriteToken error. #52369

Closed
1 task done
bbhxwl opened this issue Nov 26, 2023 · 14 comments
Closed
1 task done

Net8 uses the new JwtSecurityTokenHandler() WriteToken error. #52369

bbhxwl opened this issue Nov 26, 2023 · 14 comments
Labels
area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved

Comments

@bbhxwl
Copy link

bbhxwl commented Nov 26, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I am in net6, and this code can be used normally. However, there was an error in net8,
The length of the SecretKey is 16

SymmetricSecurityKey key =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSettings.SecretKey));
image

Claim[] claims = new Claim[]
            {
                new Claim("UserInfo", JsonConvert.SerializeObject(c)),
                new Claim(ClaimTypes.Role, roleStr),
            };
            SymmetricSecurityKey key =
                new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSettings.SecretKey));
            JwtSecurityToken token = new JwtSecurityToken(
                issuer: JwtSettings.Issuer,
                audience: JwtSettings.Audience,
                claims: claims,
                notBefore: DateTime.Now,
                expires: DateTime.Now.AddDays(7),
                signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
            );
            string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);

Expected Behavior

No response

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

No response

Anything else?

No response

@bbhxwl
Copy link
Author

bbhxwl commented Nov 26, 2023

How can I allow the key length to be compatible with my previous version?

@martincostello
Copy link
Member

The underlying change to increase the minimum key sizes is due to changes in v7 of the IdentityModel libraries, which ASP.NET Core 8 depends on, so I think this question is best suited for the https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet repo.

@bbhxwl
Copy link
Author

bbhxwl commented Nov 26, 2023

The underlying change to increase the minimum key sizes is due to changes in v7 of the IdentityModel libraries, which ASP.NET Core 8 depends on, so I think this question is best suited for the https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet repo.

Is there anything else I can do besides increasing the length of the key?

@martincostello
Copy link
Member

I'm not aware of a way to force a smaller key size to be used.

FYI this was the change that increased the minimum key length: AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet#2072

@Tratcher Tratcher added area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer and removed area-security labels Nov 27, 2023
@vincywindy
Copy link

I ran into the same issue where I thought the old keys should be compatible to provide seamless migration, but it didn't work.

options.TokenValidationParameters = new TokenValidationParameters
{
    ValidateIssuerSigningKey = true,
    IssuerSigningKeys = new[] {
         new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Authentication:JwtBearer:SecurityKey256"])),
         new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Authentication:JwtBearer:SecurityKey"])),
    },


    // Todo
 
};

The old key (192bit) doesn’t work,throw the same problem.
image

@joaopaulopmedeiros
Copy link

joaopaulopmedeiros commented Dec 5, 2023

I've gotten similar behavior as i've upgraded from net7.0 to net8.0
screenshot-issue

@bbhxwl
Copy link
Author

bbhxwl commented Dec 6, 2023

I've gotten similar behavior as i've upgraded from net7.0 to net8.0 screenshot-issue

This is C #, and upgrading usually does not consider compatibility, just like when I studied Winphone7 and Winphone8 before, there were significant changes in the API.

@VitaliyMF
Copy link

How can I allow the key length to be compatible with my previous version?

I faced the same issue during migration of my product to net8: JWTs are used by end-users for accessing API from 3rd parties (like Zapier or PowerAutomate) and it is really painful to force all users to re-generate and update their JWTs. I've reviewed CryptoProviderFactory code and tried to find an option to enable some kind of 'compatibility' mode and surprisingly didn't find any way to suppress ValidateKeySize calls (no good for sure - this is a very core lib and backward compatibility should be top-priority to allow smooth net6 to net8 apps migration, at least by explicit setting of some special TokenValidationParameters prop).

It seems that extending key size with zeros keeps backward compatibility with previously generated JWTs (in net6 and even in netcore31). How to add this support of old 'short' keys:

  1. use TokenValidationParameters.IssuerSigningKeyResolver for JWTs validation and extend the key to appropriate minimum length, for example:
jwtParams.IssuerSigningKeyResolver = (tokenString, securityToken, identifier, parameters) => {
	string alg = null;
	if (securityToken is JwtSecurityToken jwtSecurityToken)
		alg = jwtSecurityToken.SignatureAlgorithm;
	if (securityToken is Microsoft.IdentityModel.JsonWebTokens.JsonWebToken jsonWebToken)
		alg = jsonWebToken.Alg;
	if (parameters.IssuerSigningKey is SymmetricSecurityKey symIssKey 
		&& alg!=null) {
		// workaround for breaking change in "System.IdentityModel.Tokens.Jwt 6.30.1+ 
		switch (alg?.ToLowerInvariant()) {
			case "hs256":
				return new[] { ExtendKeyLengthIfNeeded(symIssKey, 32) };
			case "hs512":
				return new[] { ExtendKeyLengthIfNeeded(symIssKey, 64) };
		}
	}
	return new[] { parameters.IssuerSigningKey };
};
SymmetricSecurityKey ExtendKeyLengthIfNeeded(SymmetricSecurityKey key, int minLenInBytes) {
	if (key != null && key.KeySize < (minLenInBytes * 8)) {
		var newKey = new byte[minLenInBytes]; // zeros by default
		key.Key.CopyTo(newKey, 0);
		return new SymmetricSecurityKey(newKey);
	}
	return key;
}
  1. in a similar way use ExtendKeyLengthIfNeeded when JWT is generated by the app.

Nothing is changed in HMAC code that actually uses the key, so extending the key with zeros allows to bypass ValidateKeySize (and keep 100% backward compatibility).

@martincostello
Copy link
Member

I'm not aware of a way to force a smaller key size to be used.

See this document for a workaround if you cannot change to a longer key: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/wiki/IDX10720

@VitaliyMF
Copy link

@martincostello in my NET8 app I tried to set

System.AppContext.SetSwitch("Switch.Microsoft.IdentityModel.UnsafeRelaxHmacKeySizeValidation", true);

but without a workaround with zeros anyway I constantly get

      System.ArgumentOutOfRangeException: IDX10720: Unable to create KeyedHashAlgorithm for algorithm 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha256', the key size must be greater than: '256' bits, key has '128' bits. (Parameter 'keyBytes')
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.ValidateKeySize(Byte[] keyBytes, String algorithm, Int32 expectedNumberOfBytes)
         at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateKeyedHashAlgorithm(Byte[] keyBytes, String algorithm)
         at Microsoft.IdentityModel.Tokens.SymmetricSignatureProvider.CreateKeyedHashAlgorithm()

(with the latest Microsoft.IdentityModel.Tokens 7.1.2)

It is unclear for me how this switch could work - I cannot find anything that checks this switch in CryptoProviderFactory code: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/rel/7.1.2/src/Microsoft.IdentityModel.Tokens/CryptoProviderFactory.cs#L490

Maybe this switch only in the case when CustomCryptorProvider is used?.. In any way, this is definitely not the case when JWT auth is enabled for MVC Core app in a standard way.

@martincostello
Copy link
Member

Maybe there's some nuance to it that isn't described in the documentation I linked to. You'd have to ask over in that repo.

@nikcio
Copy link

nikcio commented Jan 25, 2024

@VitaliyMF The switch works fine in v6.35.0. (See code here)

But it seems that this change wasn't merged on v7.1.2.

The PR is here: AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet#2421

@VitaliyMF
Copy link

The switch works fine in v6.35.0. (See code here)

But it seems that this change wasn't merged on v7.1.2.

Hope it will be merged into 7.x branch soon. For now, my workaround works just fine - for all version (old 6.x, 6.30+ and 7.x) (and already used in production).

@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@wtgodbe wtgodbe removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@wtgodbe wtgodbe removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 13, 2024
@dotnet dotnet deleted a comment from dotnet-policy-service bot Feb 13, 2024
@dotnet dotnet deleted a comment from dotnet-policy-service bot Feb 13, 2024
@mkArtakMSFT
Copy link
Member

Thanks for answering this, @martincostello! Closing as no further action is pending here.

@mkArtakMSFT mkArtakMSFT added the ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. label Mar 13, 2024
@mkArtakMSFT mkArtakMSFT closed this as not planned Won't fix, can't repro, duplicate, stale Mar 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved
Projects
None yet
Development

No branches or pull requests

9 participants