0

I'm new in JWT authentification, so maybe what i want to do is wrong.

I'm using asymmetric RSA key pair to sign and validate JWT.

In my startup.cs I've :

 public void ConfigureServices(IServiceCollection services) {
            services.AddControllers();
          
            services.AddSingleton<RsaSecurityKey>(provider => {
                RSA rsa = RSA.Create();
                rsa.ImportRSAPublicKey(
                    source: Convert.FromBase64String(configuration["Jwt:PublicKey"]),
                    bytesRead: out int _
                );
                
                return new RsaSecurityKey(rsa);
            });
            services.AddAuthentication()
                .AddJwtBearer("Asymmetric", options => {
                    SecurityKey rsa = services.BuildServiceProvider().GetRequiredService<RsaSecurityKey>();
                    
                    options.TokenValidationParameters = new TokenValidationParameters {
                        IssuerSigningKey = rsa,
                        ValidAudience = "audience-test",
                        ValidIssuer = "test-issuer",
                        RequireSignedTokens = true,
                        RequireExpirationTime = true,
                        ValidateLifetime = true,
                        ValidateAudience = true,
                        ValidateIssuer = true,
                    };
                });
        }

To generate my token I've in my controller :

[HttpPost]
        [Route("Asymmetric")]
        public IActionResult GenerateTokenAsymmetric()
        {
            using RSA rsa = RSA.Create();
            rsa.ImportRSAPrivateKey(
                source: Convert.FromBase64String(_configuration["Jwt:PrivateKey"]),
                bytesRead: out int _);

            var signingCredentials = new SigningCredentials(
                key: new RsaSecurityKey(rsa),
                algorithm: SecurityAlgorithms.RsaSha256
            );

            DateTime jwtDate = DateTime.Now;

            var jwt = new JwtSecurityToken(
                audience: "test-audience",
                issuer: "test-issuer",
                claims: new Claim[] { new Claim(ClaimTypes.NameIdentifier, "John") },
                notBefore: jwtDate,
                expires: jwtDate.AddMinutes(1),
                signingCredentials: signingCredentials
            );

            string token = new JwtSecurityTokenHandler().WriteToken(jwt);

            return Ok(new
            {
                jwt = token
            });
        }

As you see it, my public key is stored in my appsettings. I would like to use options.MetadataAddress so that my client can download metadata about my api and retrieve public key to validate token.

My question is :

It is possible to create a custom .well-known/openid-configuration in .net core ? Or I must to use IdentityServer for example ?

Thanks for help

Julien Martin
  • 197
  • 2
  • 15

1 Answers1

2

I don't think it is is that hard to create your own static "fake" .well-known/openid-configuration page. But at at the same time, having a dedicates token service like IdentityServer will give you advantages when your system grows. Don't forget you also need to create the JWKS endpoint as well. As the AddJwBearer handler makes requests to both.

Also you doing it all by your self also opens up potential security issues that is already fixed/solved in the existing solutions.

Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40
  • Thanks for your feedback, so I'm using IdentityServer4, in method `services.AddSigningCredential(MyCredential)`, `MyCredential` is generated by method who generate RSA key, it is a good practice to do this ? I help myself with this post [link](https://stackoverflow.com/questions/49042474/addsigningcredential-for-identityserver4) – Julien Martin Dec 10 '21 at 13:43
  • 1
    If you are using IdentityServer, you should not try to make your own. Using AddSigningCredential in production is a good idea, you just need to pass it a private key, that is how you are supposed to do it. AddSigningCredential does not create any key for you, you have to generate and create it out side IdentityServer. perhaps using Openssl or Azure Key Vault or something similar... – Tore Nestenius Dec 10 '21 at 14:04
  • Do you want me to clarify anything in my answer? Feel free to accept it if you think it answered your question – Tore Nestenius Dec 10 '21 at 14:25
  • No it's fine for me :) I've accepted your answer, I continue my api and I'm looking for how to refresh token and if I need some help, I'll come back :) – Julien Martin Dec 10 '21 at 14:35
  • Feel free to ask more questions and I will try to answer them! – Tore Nestenius Dec 10 '21 at 14:36
  • For refresh token, they are supported for the following flows : authorization code, hybrid and resource owner password credential flow, but not for ClientCredentials. So, I need to request a new request token or call RequestRefreshTokenAsync on client side ? Thanks for help – Julien Martin Dec 10 '21 at 15:39
  • it is always good to create new questions, to avoid this to become a chat :-) But if you want to follow best practices (OAuth 2.1) then you should only consider authorization code flow or client credentials flow. For client credentials flow, there is no point of having refresh tokens as the there is no real human user involved. The client can just authenticate again to get a new access token. How you use the refresh tokens depends on the libraray. – Tore Nestenius Dec 10 '21 at 15:50
  • Sorry, do you want I create a new question ? Otherwise thanks for your help – Julien Martin Dec 10 '21 at 16:04
  • Create a new question, then the question and answer is more easily found by others :-) Feel free to create a new question. – Tore Nestenius Dec 10 '21 at 16:07
  • aha, you created it as an answer instead of a question, well, perhaps remove it and keep it as it is for now...? makes it a bit confusing as it is now :-) – Tore Nestenius Dec 10 '21 at 16:22
  • I'm trying to create a fake'ish JWKS endpoint but can't really figure out what to put where. I mimic whatever IDS4 serves but it's a bunch of cryptic abbreviations and I get lost in the trial and horror. Haven't found any good resources explaining the minimal JSON to return on the endpoint. Got any hints? – Konrad Viltersten Jan 22 '23 at 18:37
  • You should be able to figure that out by exploring how IdenityServer does it in their code here https://github.com/DuendeSoftware/IdentityServer/blob/main/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs – Tore Nestenius Jan 23 '23 at 09:48