简体   繁体   中英

What is the easiest way to validate the signature of a JWT token?

First some code... I have a Security class:

public static class Security
{
    public static RSACryptoServiceProvider RSA { get; } = new(4096);
    public static SigningCredentials Credentials()
    {
        return new SigningCredentials(new RsaSecurityKey(RSA), SecurityAlgorithms.RsaSha512)
        {
            CryptoProviderFactory = new CryptoProviderFactory { CacheSignatureProviders = false }
        };
    }

}

This is a simple static class that generates an RSA key and related signing credentials. It has some more code but that's not important for my question...
Then I have code to generate a JWT token using System.IdentityModel.Tokens.Jwt and System.Security.Claims :

    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Jti, account.Id.ToString()),
        new Claim(JwtRegisteredClaimNames.Sub, account.Name),
        new Claim(JwtRegisteredClaimNames.Name, account.FullName),
        new Claim(JwtRegisteredClaimNames.GivenName, account.FirstName),
        new Claim(JwtRegisteredClaimNames.FamilyName, account.LastName),
        new Claim(JwtRegisteredClaimNames.Birthdate, account.Birthdate.ToString()),
        new Claim(JwtRegisteredClaimNames.Email, account.Email.ToString()),
    };
    var token = new JwtSecurityToken
    (
        issuer: host,
        audience: audience,
        claims: claims,
        notBefore: DateTime.UtcNow,
        expires: DateTime.UtcNow.AddHours(4),
        Security.Credentials()
    );

Again, not too challenging. A few claims from data in my code, which is my own class with basic user data. And this is turned into a token that is signed. It results in this token:

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhYmQ3NjUxMS1jNmNmLTQzZjUtOGE1Zi1iZjEzZTg0NGM1ZmEiLCJzdWIiOiJ3aW0iLCJuYW1lIjoiV2ltIFRlbiBCcmluayIsImdpdmVuX25hbWUiOiJXaW0iLCJmYW1pbHlfbmFtZSI6IlRlbiBCcmluayIsImJpcnRoZGF0ZSI6IjExLTctMTk2NiIsImVtYWlsIjoid2ltQGV4YW1wbGUuY29tIiwibmJmIjoxNjQwNjU1MDA1LCJleHAiOjE2NDA2Njk0MDUsImlzcyI6ImxvY2FsaG9zdDo3MTkwIiwiYXVkIjoiL1Rva2VuL0xvZ2luIn0.iFn6DKvHxW_Vd6bxlLs4quQwCyYWpL7bbyMJSTVMxS4RRQ9GxM9IvgoymEqyn9YNBc68TFULNPRVBFE8_mF-IpYt1NIGtp8p7u9laMRegEfXyvJFislDcPZoMbD5xjB18xwUwTpkNjdX4svzFIR8mQT5bLcb5BojFLhxUVT-oJ8G_f0lD0XWJkDo40OW9aHECjIOOu_KfeYZiPdiuo-q9yed6WN1-dgqz4ykWOYC7FoMA0ZYogG5pRvmVLOq8haiEDEJRszbhjj6CLt6h_hlwOS0mMZF6a7Ag5mN4lI2UtEot-jYyXM72eXgBPm_bWNsa6RG_m9vFf4EElK4ekfFd3V_qkAnZ8XEhfTcRD8ASEVjXg8hTI5SY4LFyrggso44HFN5oEoVWlVVcGZxEG2R6LspJSFD4xkrVUUeQvt7IbBL1ViflSfGYp6-cLMPfxo3qZvItC7DxP_8aAygNmHi0_T8BxGNLnOwqrPtDOjKzw4SqEEwBf5S5R6O_dufhauAVvvS_rKQnkEdq-MNNNW5U90ytauCcAgFEGa03MN3E4hhQKUE5y70wCStrIFcBtJezf32U8V7SHv1WrVMpnQXxQoLneZh3b7QsthKCh49ypUSLjw 4yL9VVur2K0oV8NsLnwoqH5dCVFuq7YHmreiTa-ZUIFVrgWYMzMqR8hG7Ato

And now I want to convert it back to a token by using this code:

var tokenData = new JwtSecurityToken(tokenString);

And that will generate the token from the string again, but it's not verified, of course. And I need to verify the signature for this token.
To be clear: this is NOT for an ASP.NET Core application but I do use .NET Core for this console application. This is a simple tool that connects to a database which contains tokens as strings and it just has to validate every token inside it with a specific RSA key. (Also stored in a safe location.) Tokens in this database come from a web application which uses this table for logging purposes but apparently some tokens get signed with a wrong or invalid key and I need a quick way to find which tokens are invalid in this log.

So, what is the easiest way to validate these signatures?


And an update: My code is using Microsoft.AspNetCore.Authentication.JwtBearer and for some reason it caused some unexpected behavior and errors during validations. When I kicked it out and replaced it withSystem.IdentityModel.Tokens.Jwt it all starts to work.
Both packages are very similar in classes and other parts, and I'm not sure how they differ from one another, but they do differ. One is to work with OpenID and the other one for JWT in general. Switching to the last one solved my problems...

If you're not limited to the language, you can use a library that we created at Curity for validating JWTs: https://www.npmjs.com/package/@curity/jwt-validation . We've also created a list of libraries which you can use to validate JWTs: https://curity.io/resources/guides/libraries/api/ so if you want to stick to .NET you can find a library there. We also have a tutorial which shows how to use that .NET lib: https://curity.io/resources/learn/dotnet-api/

As it turns out, it seems to be a bug in package Microsoft.AspNetCore.Authentication.JwtBearer but the package System.IdentityModel.Tokens.Jwt is near-identical but got the job done.The following code just works:

        var param = new TokenValidationParameters
        {
            ClockSkew = TimeSpan.FromMinutes(5),
            ValidateAudience = true,
            ValidateIssuer = true,
            ValidateIssuerSigningKey = true,
            ValidateTokenReplay = false,
            ValidateLifetime = true,
            IssuerSigningKey = new RsaSecurityKey(Security.RSA),
            ValidAudience = Audience,
            ValidIssuer = Issuer,
        };
        var claim = new JwtSecurityTokenHandler().ValidateToken(tokenString, param, out _);
        if (claim == null) throw new InvalidSignature(tokenString);

(But with the Bearer library ir failed. Not sure why.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM