2

I want to build a JWT Security Token Service(.net core 2+) to provide authentication and authorization to many APIs(.net core 2+) without using IdentityServer or OAuth because I want no redirections.

The "JWT Authenticator" is working fine and has the routes

  • POST Account: register new user
  • POST Auth/Login: return a jwt token if credentials are valid
  • POST Token: refresh the token
  • POST Token/Revoke: revoke the token

However, I'm struggling to provide steps 4 and 5. I tried many options at API1/Startup.cs -> ConfigureServices, and couldn't get any results but 404 when calling GET API1/Resource. The ConfigureServices method is still this:

 public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
       .AddJwtBearer(options =>
       {
           options.Authority = "http://localhost:6000"; // JWT Authenticator address
           options.RequireHttpsMetadata = false;
           options.SaveToken = true;
           options.TokenValidationParameters = new TokenValidationParameters
           {    
               ValidIssuer = _configuration.GetValue<string>("JwtIssuer"),
               ValidAudience = _configuration.GetValue<string>("JwtAudience"),
               IssuerSigningKey = new SymmetricSecurityKey(
                   Encoding.UTF8.GetBytes(_configuration.GetValue<string>("JwtSecretKey"))),
               ClockSkew = TimeSpan.Zero
           };
       });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

Is it possible to configure steps 4 and 5 using a method like AddJwtBearer? If not, what should I do? Use an Authorization Filter to API1 to intercept requests and make a request to JWT Authenticator to validate the token/get claims/etc?

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
  • Looks like you just reinvented resource owner password flow. Anyway, JWTs are not normally revalidated with backchannel calls because they prove issuer and validity using asymetric encryption. – Vidmantas Blazevicius Apr 14 '19 at 20:08
  • _“because I want no redirections”_ – Redirects are just a part of few specific auth flows in OAuth, and are mainly there to protect the user because the application cannot be trusted with a password. That does not mean that there aren’t flows that allow this **if** you can trust the app. – Implementing your own authentication protocol is usually a very bad idea simply because it is *very hard*. So I would recommend you to instead use existing protocols and well tested libraries that implement these. – poke Apr 14 '19 at 20:16

1 Answers1

0

Some thoughts...

Your 4 & 5 paths; normally you don't ask the provider of the token if it is valid. What you do is verify this, most likely with a signature, which parameters can - optionally - be downloaded from the provider.

Note the subtle difference: the provider itself doesn't check it.

Next: ClockSkew = TimeSpan.Zero, this is very little. I would at least give it some sort of slack.

And at least; having a 404 indicates that a resource is not found. It's not a 401 or 403. This suggest authorization is successful but the requested resource is not found.


A typical implementation for signature validation:

note this doesn't solve your 404.

options.TokenValidationParameters = new TokenValidationParameters
{
    IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
    {
        // get from provider 
        // todo: cache this
        var json = new WebClient().DownloadString(
             issuer + "/.well-known/jwks.json"); //typical endpoint

        // serialize the result
        var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
        // cast the result to be the type expected by IssuerSigningKeyResolver
        return (IEnumerable<SecurityKey>) keys;
    }
//...
Stefan
  • 17,448
  • 11
  • 60
  • 79