title: ASP.NET Core 3.1 JWT signature invalid when using AddJwtBearer()
body: <p><strong>Problem: <code>AddJwtBearer()</code> is failing, but verifying the token manually works.</strong>
  <br><br>
  I'm trying to generate and verify a JWT with an asymmetric RSA algo.</p>
  <p>I can generate the JWT just fine using this demo code</p>
  <pre><code>[HttpPost(&quot;[action]&quot;)]
  [Authorize]
  [ValidateAntiForgeryToken]
  public async Task&lt;IActionResult&gt; JwtBearerToken() {
      AppUser user = await userManager.GetUserAsync(User);
  
      using RSA rsa = RSA.Create(1024 * 2);
      rsa.ImportRSAPrivateKey(Convert.FromBase64String(configuration[&quot;jwt:privateKey&quot;]), out int _);
      var signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256);
  
      var jwt = new JwtSecurityToken(
          audience: &quot;identityapp&quot;,
          issuer: &quot;identityapp&quot;,
          claims: new List&lt;Claim&gt;() {new Claim(ClaimTypes.NameIdentifier, user.UserName)},
          notBefore: DateTime.Now,
          expires: DateTime.Now.AddHours(3),
          signingCredentials: signingCredentials
      );
  
      string token = new JwtSecurityTokenHandler().WriteToken(jwt);
  
      return RedirectToAction(nameof(Index), new {jwt = token});
  }
  </code></pre>
  <p><br><br>
  I'm also able to verify the token and it's signature using the demo code below</p>
  <pre><code>[HttpPost(&quot;[action]&quot;)]
  [ValidateAntiForgeryToken]
  public IActionResult JwtBearerTokenVerify(string token) {
      using RSA rsa = RSA.Create();
      rsa.ImportRSAPrivateKey(Convert.FromBase64String(configuration[&quot;jwt:privateKey&quot;]), out int _);
  
      var handler = new JwtSecurityTokenHandler();
      ClaimsPrincipal principal = handler.ValidateToken(token, new TokenValidationParameters() {
          IssuerSigningKey = new RsaSecurityKey(rsa),
          ValidAudience = &quot;identityapp&quot;,
          ValidIssuer = &quot;identityapp&quot;,
          RequireExpirationTime = true,
          RequireAudience = true,
          ValidateIssuer = true,
          ValidateLifetime = true,
          ValidateAudience = true,
      }, out SecurityToken securityToken);
  
      return RedirectToAction(nameof(Index));
  }
  </code></pre>
  <p><br><br>
  But, verification fails (401) when hitting an endpoint protected with<br />
  <code>[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]</code></p>
  <p>Error message from HTTP header: Bearer error=&quot;invalid_token&quot;, error_description=&quot;The signature is invalid&quot;</p>
  <p><br><br>
  My JWT bearer auth configuration is here</p>
  <pre><code>.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =&gt; {
      using var rsa = RSA.Create();
      rsa.ImportRSAPrivateKey(Convert.FromBase64String(Configuration[&quot;jwt:privateKey&quot;]), out int _);
                      
      options.IncludeErrorDetails = true;
      options.TokenValidationParameters = new TokenValidationParameters() {
          IssuerSigningKey = new RsaSecurityKey(rsa),
          ValidAudience = &quot;identityapp&quot;,
          ValidIssuer = &quot;identityapp&quot;,
          RequireExpirationTime = true,
          RequireAudience = true,
          ValidateIssuer = true,
          ValidateLifetime = true,
          ValidateAudience = true,                 
      };
  });
  </code></pre>
  <p><strong>I can easily make it work using a symmetric key and HmacSha256 - but that's not what I'm looking for.</strong></p>
  <br>
  <h2>UPDATE</h2>
  <p>I've written the exception to the response, and this is what I get:</p>
  <pre><code>IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: '', InternalId: '79b1afb2-0c85-43a1-bb81-e2accf9dff38'. , KeyId: 
  '.
  Exceptions caught:
   'System.ObjectDisposedException: Cannot access a disposed object.
  Object name: 'RSA'.
     at System.Security.Cryptography.RSAImplementation.RSACng.ThrowIfDisposed()
     at System.Security.Cryptography.RSAImplementation.RSACng.GetDuplicatedKeyHandle()
     at System.Security.Cryptography.RSAImplementation.RSACng.VerifyHash(ReadOnlySpan`1 hash, ReadOnlySpan`1 signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
     at System.Security.Cryptography.RSAImplementation.RSACng.VerifyHash(Byte[] hash, Byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
     at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.VerifyWithRsa(Byte[] bytes, Byte[] signature)
     at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.Verify(Byte[] bytes, Byte[] signature)
     at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.Verify(Byte[] input, Byte[] signature)
     at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, TokenValidationParameters validationParameters)
     at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
  '.
  token: '{&quot;alg&quot;:&quot;RS256&quot;,&quot;typ&quot;:&quot;JWT&quot;}.{&quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&quot;:&quot;mail@mail.com&quot;,&quot;nbf&quot;:1582878368,&quot;exp&quot;:1582889168,&quot;iss&quot;:&quot;identityapp&quot;,&quot;aud&quot;:&quot;identityapp&quot;}'.
  </code></pre>
  <br>
  <h2>UPDATE - Working solution</h2>
  <p>So, I guess I figured it out from the exception message. The RSA security key was being prematurely disposed.</p>
  <p>I extracted the key creation from the <code>AddJwtBearer()</code>, and used dependency injection instead.</p>
  <p>This seems to work just fine. But I'm unsure if this is good practice.</p>
  <pre><code>// Somewhere futher up in the ConfigureServices(IServiceCollection services) method
  services.AddTransient&lt;RsaSecurityKey&gt;(provider =&gt; {
      RSA rsa = RSA.Create();
      rsa.ImportRSAPrivateKey(
          source: Convert.FromBase64String(Configuration[&quot;jwt:privateKey&quot;]),
          bytesRead: out int _);
                  
          return new RsaSecurityKey(rsa);
  });
  
  
  // Chaining onto services.AddAuthentication()
  .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =&gt; {
      SecurityKey rsa = services.BuildServiceProvider().GetRequiredService&lt;RsaSecurityKey&gt;();
                      
          options.IncludeErrorDetails = true;
          options.TokenValidationParameters = new TokenValidationParameters() {
          IssuerSigningKey = rsa,
          ValidAudience = &quot;identityapp&quot;,
          ValidIssuer = &quot;identityapp&quot;,
          RequireExpirationTime = true,
          RequireAudience = true,
          ValidateIssuer = true,
          ValidateLifetime = true,
          ValidateAudience = true,
      };
  
  });
  </code></pre>