Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Validate JWT token generated from one app in another?

Firstly, thank you for taking the time to read this.

I have a need to validate JWT tokens generated by one .net core 2.2 application in another .net core 3.1 application.

Currently, I'm unable to use the .net core authorization to validate the token but am able to write a separate method to validate the token. I've ensured that the secret used to sign the tokens are the same.

How can I use the built in authentication in .net core 3.1 to validate the token generated from a different application.

Below is a detailed description:

I created an API for login requests that generates a JWT token for validation on .net core 2.2 using this tutorial.

In my Login API, at startup.cs, I've added authentication as follows:

        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });

I generate the token like this:

        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.Name, dbUser.UserID.ToString())
            }),
            Expires = DateTime.Now.AddMinutes(_appSettings.Expiry_Min),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
            Audience = _appSettings.Audience,
            Issuer = _appSettings.Issuer,
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);

The JWT token works great. In my controller, I add the [Authorize] attribute and requests with invalid tokens are immediately rejected.

Now, I want to validate the token being generated by my login API in another Application in .net core 3.1 to validate the login response. To do this, I referred to this tutorial. In the startup.cs of this second application, I have:

    private void SetupJWTServices(IServiceCollection services)
    {
        // configure strongly typed settings objects
        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);

        // configure jwt authentication
        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);

        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });

This method, is called as follows:

    public void ConfigureServices(IServiceCollection services)
    {
        SetupJWTServices(services);            
        services.AddControllers();

        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);
    }

In my second application, when I use the [Authorize] attribute, the request is immediately rejected with 401, unauthorized. However, when I do not use the [Authorize] attribute and create a method to validate the token, the method is able to validate all valid requests. The method I wrote is:

    private void Validator(string token)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var appSettingsSection = _appConfiguration.GetSection("AppSettings");
        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);
        try
        {
            tokenHandler.ValidateToken(token, new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
                ClockSkew = TimeSpan.Zero
            }, out SecurityToken validatedToken);

            var jwtToken = (JwtSecurityToken)validatedToken;

            // return account id from JWT token if validation successful
        }
        catch
        {
            // return null if validation fails
        }

This implies to me that to validate all requests, I need to first pass it through this validator method before I process anything. However, this is not using the built in authorization controls. It doesn't seem right.

Is this how JWT tokens are to be validated between different applications?

like image 384
Sathya Avatar asked Dec 02 '20 02:12

Sathya


1 Answers

Use Claims to validated Token

static public bool ValidacionTokenManual(string Token, string secretKey, string audienceToken, string issuerToken)
    {
        TokenValidationParameters validationParameters = new TokenValidationParameters()
        {
            ValidAudience = audienceToken,
            ValidIssuer = issuerToken,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(secretKey))
        };

        SecurityToken validateToken;
        JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();

        if(handler.CanReadToken(Token))
        {
            var user = handler.ValidateToken(Token, validationParameters, out validateToken);

            string roles = user.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role)?.Value;
            if(roles != "")
            {
                return true;
            }
        }

        return false;
    }
like image 68
FranRam Avatar answered Oct 28 '22 04:10

FranRam