3

So this is how I validate a JWT bearer token in backend:

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.Authority = $"https://{Configuration["Auth0:Authority"]}";
                options.Audience = Configuration["Auth0:Audience"];
            });

It works fine as .Net core consults with the authority to get required info (such as signing key) under the hood. In my case it talks to Auth0 servers via https://< MY TENANT > .auth0.com/.well-known/openid-configuration.

The problem is my application cannot talk to the Auth0 server when I deploy it in an Intranet which doesn't have access to the internet. Here's the error I get:

System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://< My TENANT >.auth0.com/.well-known/openid-configuration'.

I tried feeding RSA key manually, but not luck and same error:

AddJwtBearer(options =>
            {
                options.Authority = $"https://{Configuration["Auth0:Domain"]}";
                options.Audience = Configuration["Auth0:Audience"];
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateLifetime = true,
                    RequireSignedTokens = true,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = GetRsaKey(),
                };
            }); 

 private SecurityKey GetRsaKey()
        {
            byte[] modulus = Decode("r5cpJ....-fUGjJCH1QQ");
            byte[] exponent = Decode("A...AB");

            var rsaParameters = new RSAParameters
            {
                Modulus = modulus,
                Exponent = exponent
            };

            using var rsaProvider = new RSACryptoServiceProvider();
            rsaProvider.ImportParameters(rsaParameters);
            return new RsaSecurityKey(rsaProvider);
        }

Any workaround?

Hans
  • 2,674
  • 4
  • 25
  • 48

3 Answers3

3

Since you do not have access to the internet you need to have on-premise identity and access control like Identity Server, or create your own JWT Issuer/Validator as follows:

  1. Get a private key.
  2. Whenever the user logs in, generate a JWT security token:
private JwtSecurityToken GetJwtSecurityToken(List<Claim> user_claims)
{
     string privateKey = "YOUR_PRIVATE_KEY";
     var symmetricKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(privateKey));
     var credentials = new SigningCredentials(symmetricKey, SecurityAlgorithms.HmacSha256);

     return new JwtSecurityToken
     (
          issuer: "ISSUER_NAME",
          audience: "AUDIENCE",
          claims: user_claims,
          signingCredentials: credentials
     );
}
  1. Serialize the JWT (from step 2):
var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
  1. Send the token to the user or add it to the cookies.

  2. In your startup file:

services.AddAuthentication()
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, config =>
    {
        config.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "ISSUER",
            ValidAudience = "AUDIENCE",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YOUR_PRIVATE_KEY"))
         };
});
  1. Secure your Controllers by adding:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

That's all. And hopefully someone will tell us if there is any better solution.


Update 1 (adding a reference):

Check this article Securing ASP.NET Core 2.0 Applications with JWTs.

Hameed
  • 1,497
  • 9
  • 12
3

TokenValidationParameters can be used in scenario that you want to validate tokens without access to the issuing server. Then you can not set the Authority , setting ValidateIssuerSigningKey and ValidateIssuer , and finally set IssuerSigningKey which is the public key used for validating incoming JWT tokens. Here and here are code samples.

But the problem is because you can't talk to Auth0 , that means you can't get the latest publick key to validate the token which issued by Auth0 , you should confirm that your local public key sync with the newest publich ones by Auth0 . If authentication is also controlled by you , you can consider using Identity Server4 which is a local authentication/SSO framework , or you can implement JWT authentication as shown here .

Nan Yu
  • 26,101
  • 9
  • 68
  • 148
1

The answer by Nan Yu is very accurate and you have these high level options:

  • Configure a fixed key and validate tokens with it in the back end. This will work for a while but could break really badly in future, if keys are not synched reliably, and Auth0 renews the token signing keys, possibly leading to serious problems for your company.

  • Ensure that your back end has outbound connectivity to Auth0, as a trusted provider, so that the system can work reliably in the simplest and most standard way.

This feels like a people and process problem rather than a technical one. I would not try to solve it via code changes.

I suspect the IT administrators are trying to enforce an outdated no internet policy that is against your company's interests. At an IT level it is easy to whitelist only Auth0 URLs and block others.

As a next step I would try to convince your stakeholders / bosses to support the standard setup - perhaps forward them this post.

Gary Archer
  • 22,534
  • 2
  • 12
  • 24