3

I'm trying to get dual authentication schemes working with Azure Ad and regular jwt tokens, the issue i'm having is, I can access both controller functions with just the JWT token, regardless of scheme. I tried setting up my configuration from this post but it didn't work (neither does my current configuration obviously):

Authenticating tokens from multiple sources (e.g Cognito and Azure)

[HttpGet]
    [Authorize(AuthenticationSchemes = "TestBearer")]
    [Route("Test1")]
    public async Task Test()
    {

    }

    [HttpGet]
    [Authorize(AuthenticationSchemes = "AzureAd")]
    [Route("Test2")]
    public async Task Test2()
    {

    }

Startup config

services.AddAuthentication(options =>
                {
                    options.DefaultScheme = "AzureAd";
                })
                .AddJwtBearer("TestBearer", x =>
                {
                    x.RequireHttpsMetadata = false;
                    x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                    {
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        ValidateLifetime = false,
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Guid.Parse(jwtConfig.SecretKey).ToByteArray())
                    };
                })
            .AddMicrosoftIdentityWebApi(x =>
            {
                x.Audience = config.Audience;
                x.Authority = config.Authority;
                x.RequireHttpsMetadata = false;
            },
            x =>
            {
                x.Instance = config.Instance;
                x.ClientId = config.ClientId;
                x.TenantId = config.TenantId;
                x.Authority = config.Authority;
                x.RequireHttpsMetadata = false;
            }, "AzureAd");
            services.AddAuthorization(options =>
            {
                var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
           "TestBearer", "AzureAd");
                defaultAuthorizationPolicyBuilder =
            defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
                options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
            });


            var scopes = new string[] { "https://graph.microsoft.com/.default" };

            IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
                .Create(config.ClientId)
                .WithTenantId(config.TenantId)
                .WithClientSecret(config.ClientSecret)
                .Build();

            //Build the Microsoft Graph client.As the authentication provider, set an async lambda
            //  which uses the MSAL client to obtain an app-only access token to Microsoft Graph,
            // and inserts this access token in the Authorization header of each API request.
            var authenticationProvider = (new DelegateAuthenticationProvider(async (requestMessage) =>
                 {
                     // Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
                     var authResult = await confidentialClientApplication
                          .AcquireTokenForClient(scopes)
                          .ExecuteAsync();

                     //// Add the access token in the Authorization header of the API request.
                     requestMessage.Headers.Authorization =
                          new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
                 }));

            services.AddScoped(_ => new GraphServiceClient(authenticationProvider));

my jwt token generation

private string GenerateToken(TestEntity entity)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Guid.Parse(_jwtSettings.SecretKey).ToByteArray();

            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]{
                            new Claim(ClaimTypes.NameIdentifier, entity.Id.ToString()),
                            new Claim(ClaimTypes.MobilePhone, entity.Phone.ToString()),
                            new Claim(ClaimTypes.Email, entity.Email)
                        }),
                Expires = DateTime.UtcNow.AddHours(_jwtSettings.ExpiryTimeInHours),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),

            Audience = "https://localhost:5001", 
             Issuer = _jwtSettings.Issuer,
            };

            var token = tokenHandler.CreateToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }

1 Answers1

0

So I ended up seperating the policies (leaving azure AD as my default policy) and creating an extra combined one in cases I want one of multiple policies to work. All seems to work correctly now.

services.AddAuthorization(options =>
            {
                options.AddPolicy("Test", policy =>
                {
                    policy.AuthenticationSchemes.Add("TestBearer");
                    policy.RequireAuthenticatedUser();
                });

            options.AddPolicy("AzureOrTest", policy =>
                {
                policy.AuthenticationSchemes.Add("TestBearer");
                    policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
                    policy.RequireAuthenticatedUser();
                });

                options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
                .RequireAuthenticatedUser()
                .Build();
            });