0

I have added a middleware to handle the token validation in the backend .NET core 3.1 project.

Startup.cs changes

app.UseRouting();
app.UserAuthorization();
app.UserMiddleware<JWTMiddleware>();

JWTMiddleware.cs

    using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WebAPI
{
    public class JwtMiddleware
    {
        private readonly RequestDelegate _next;
        //private readonly AppSettings _appSettings;

        //public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
        public JwtMiddleware(RequestDelegate next)
        {
            _next = next;
            //_appSettings = appSettings.Value;
        }

        public async Task Invoke(HttpContext context)
        {
            var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

            if (token != null)
                await attachAccountToContext(context, token);

            await _next(context);
        }

        private async Task attachAccountToContext(HttpContext context, string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var secretkey="";
                var key = Encoding.ASCII.GetBytes(secretKey);
                var clientID = "MYCLIENTID";
                tokenHandler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidIssuer= "https://login.microsoftonline.com/MYTENNANTID/v2.0",
                    ValidAudience=clientID,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    
                    ClockSkew = TimeSpan.Zero,
                    
                }, out SecurityToken validatedToken);

                var jwtToken = (JwtSecurityToken)validatedToken;
                var accountId = int.Parse(jwtToken.Claims.First(x => x.Type == "upn").Value);

                // attach account to context on successful jwt validation
                context.Items["Account"] = accountId;
            }
            catch(Exception ex)
            {

                // do nothing if jwt validation fails
                // account is not attached to context so request won't have access to secure routes
            }
        }
    }
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeAttribute : Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var UserId = context.HttpContext.Items["Account"];
            if (UserId == null)
            {
                // not logged in
                context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
            }
        }
    }
}

The issue is, the Validation always fails. It gives an exception.

enter image description hereWhere do I find the key. I have added the application in Azure portal,and got a clientID and created a secret. After that I generate a token on the UI using those details, and add it in the Authorization header and pass it to the API project where it should be validated. I know something is wrong in the way the IssuerSigningKey is created, but not able to figure out what it is. I have tried passing the secret as the key but that doesn't work as well.

Auro
  • 61
  • 1
  • 8
  • 1
    Why not use the built-in JWT authentication? You define the authority and audience for it and it'd handle a lot of this for you. – juunas Oct 19 '21 at 07:15
  • Could you help me me some links, I am new to .net core and everywhere I am getting is using a custom middleware for authentication. – Auro Oct 19 '21 at 08:17
  • 1
    This sample is good at least: https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/4-WebApp-your-API/4-1-MyOrg/TodoListService. It uses the higher level Microsoft.Identity.Web library for authentication. You can find more samples here: https://learn.microsoft.com/en-us/azure/active-directory/develop/sample-v2-code – juunas Oct 19 '21 at 08:20

1 Answers1

0

This is what I tried,that helped me

var tokenHandler = new JwtSecurityTokenHandler();
            string secretKey = _configuration.GetValue<string>("AzureSSO:Secret");
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.ImportParameters(
              new RSAParameters()
              {
                  Modulus = FromBase64Url(_configuration.GetValue<string>("AzureSSO:Modulus")),
                  Exponent = FromBase64Url(_configuration.GetValue<string>("AzureSSO:Exponent"))
              });
            var clientID = _configuration.GetValue<string>("AzureSSO:ClientID");
            tokenHandler.ValidateToken(token, new TokenValidationParameters
            {
                ValidIssuer= _configuration.GetValue<string>("AzureSSO:Issuer"),
                ValidAudience=clientID,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new RsaSecurityKey(rsa),
                ValidateIssuer = false,
                ValidateAudience = false,
                ClockSkew = TimeSpan.Zero,
                
            }, out SecurityToken validatedToken);

I found the Modulus and exponent from the discovery document end point and used the same to create the key.

Auro
  • 61
  • 1
  • 8