1

I have successfully implemented Single Sign on with Azure Ad and fetched profile using MS Graph API but when I try to consume my dot net web API it is showing me error Unauthorized(401) May be I am missing something in configuration,

  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "example.onmicrosoft.com",
    "ClientId": "392xxxx2-bxx4-4xxf-axxc-505bd9c6d8b4",
    "TenantId": "06xxx2xbe-9xxe-4xx8-bxxd-e1a6ebxxxxd",
    "scopes": "api://3xxxxe52-bxx4-4xxf-axx2c-505bxxxxb4/User.Read"
  }

here is my Startup.cs code

using AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using TMS.API.Configuration;
using TMS.DAL.Configuration;
using TMS.DAL.Mapper;
using Microsoft.Identity.Web;

namespace TMS.API
{
    public class Startup
    {
        public Startup(IConfiguration configuration) => Configuration = configuration;

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        { 
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApi(Configuration, "AzureAd");

            services.AddControllers();
            services.AddSwaggerGen(s =>
            {
                s.SwaggerDoc("v1", new OpenApiInfo() { Title = "TMS API", Version = "V1" });
            });
            services.AddAutoMapper(typeof(Startup));
            services.Configure<Setting>(Configuration.GetSection("Settings"));
            services.RegisterEngineServices();
            services.RegisterRepositories();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
            app.UseCors(x => x
                 .AllowAnyOrigin()
                 .AllowAnyMethod()
                 .AllowAnyHeader()
                 .WithHeaders()
                 .WithExposedHeaders());

            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "TMS v1");
            });


        }
        private static void AddAutoMapper(IServiceCollection services)
        {
            var mapperConfig = new MapperConfiguration(mc =>
            {
                mc.AddProfile(new BSRMapperClass());
            });

            IMapper mapper = mapperConfig.CreateMapper();
            services.AddSingleton(mapper);
        }
    }
}

Controller:

 [Route("api/[controller]")]
    [ApiController]
    [RequiredScope(RequiredScopesConfigurationKey ="AzureAd:scopes")]
    public class GeneralController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IGeneralService _generalService;

        public GeneralController(IGeneralService generalService, IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
        {
            _generalService = generalService;
            _configuration = configuration;
            _httpContextAccessor = httpContextAccessor;
        }
        [Authorize(Roles ="Admin")]
        [Route("[action]")]
        [HttpGet]
        public async Task<DataTransfer<IEnumerable<MonthResponseModel>>> GetMonthList()
        {
            return await _generalService.GetMonthList();
        }

React config file:

export const msalConfig = {
    auth: {
      clientId: "ddxxxx8-xxf-4xxd-bxx2-a4xxxxxd6c",
      authority: "https://login.microsoftonline.com/061f82be-9xxe-4xx8-bdad-e1xxxxxb6d", // This is a URL (e.g. https://login.microsoftonline.com/{your tenant ID})
      redirectUri: "http://localhost:3001", 
    },
    cache: {
      cacheLocation: "sessionStorage", // This configures where your cache will be stored
      storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
    }
  };
 export const apiConfig = {
    uri: "https://example.azurewebsites.net/api", // e.g. http://localhost:5000/api
    scopes: ["api://3xxxx2-bxx4-4xxf-a72c-505xxxxx8b4/User.Read"] // e.g. ["scp1", "scp2"]
};
  // Add scopes here for ID token to be used at Microsoft identity platform endpoints.
  export const loginRequest = {
   scopes: ["User.Read"]
  };
  // Add the endpoints here for Microsoft Graph API services you'd like to use.
  export const graphConfig = {
      graphMeEndpoint: "https://graph.microsoft.com/v1.0/me"
  };

Here we have: Client(React) App Essentials Server(.net web API) App Essentials

I have exposed my API and added scope and authorized client Application: Exposed API

I need help as I have been stuck in this issue from a couple of days and Kindly do let me know where to add Users in Client App or in Server app?

  • when you set `scopes: ["api://392f6e52-b494-409f-a72c-505bd9c6d8b4/User.Read"]` in your react app and generate an access token, the scp cliam in the token will have value `User.Read`, so I'm afraid you need to change your appsetting as `"scopes": "User.Read"` – Tiny Wang Jun 03 '22 at 08:11
  • by the way, in your react code, you set audience as `clientId: "dde0525xxxd6c"`, so I think you have 2 azure ad application, the application with id `392f6e52-xxx-4xxxf-xxd8b4` exposed an api and you assigned this api to another azure ad app with id `dde0525xxxd6c`, but you set `"ClientId": "392f6-xx-xx-xx8b4",` in your api project, per my understanding you should set as `"ClientId": "dde0-xxx-xx-b7xx2d6c"`... I'm not sure about it.. – Tiny Wang Jun 03 '22 at 08:15
  • may be you can refer to [this](https://stackoverflow.com/a/68799358/15581227). – Tiny Wang Jun 03 '22 at 08:18
  • Yes These configurations are perfectly fine but there was an issue in Startup file and yes I changed "scopes": "api://3xxx-b4xx-40xx9-a72c-xxxx8b4/User.Read" to "scopes": "User.Read". – Alina Ishaque Sep 16 '22 at 06:43

1 Answers1

0

Issue Fixed! In appsetting I changed "scopes": "api://3xxx52-bxx4-40xf-axxc-505xxxx8b4/User.Read" to "scopes": "User.Read"and reorder the middleware in Configure Method (Startup file):

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "Loreal TMS v1");
        });
        app.UseHttpsRedirection();
        //app.UseStaticFiles();
     
        app.UseCors(x => x
             .AllowAnyOrigin()
             .AllowAnyMethod()
             .AllowAnyHeader()
            );
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }