Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure AD Multi Tenant ,.Net Core Web API with JWT Token

So I raised this question Azure AD Multi Tenant ,.Net Core Web API with MSAL(Microsoft Authentication Libary) which showed me how to turn on the error output.

Why would I be getting this now with my token, at a guess is the aud right and the iss for a multi tenant ad token?

AuthenticationFailed: IDX10511: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'YMELHT0gvb0mxoSDoYfomjqfjYU', InternalId: '2c34a300-21bb-4eb1-b3b9-1944f1be7470'. , KeyId: YMELHT0gvb0mxoSDoYfomjqfjYU
'. 
kid: 'YMELHT0gvb0mxoSDoYfomjqfjYU'. 
Exceptions caught:
 ''.
token: '
{
    "alg": "RS256",
    "typ": "JWT",
    "nonce": "bWqlNum32nkLGFA4s5lE83AEZ6hRUzqi4r4-3JMZLdw",
    "x5t": "YMELHT0gvb0mxoSDoYfomjqfjYU",
    "kid": "YMELHT0gvb0mxoSDoYfomjqfjYU"
}
.{
    "aud": "00000003-0000-0000-c000-000000000000",
    "iss": "https://sts.windows.net/abc60396-1ed0-4fa3-a3d0-597adf1366a5/",
    "iat": 1584438416,
    "nbf": 1584438416,
    "exp": 1584442316,
    "acct": 0,
    "acr": "1",
    "aio": "42NgYNh7TvzDvOILBsl/7E+U+vxP6y5rmJERnny04o5ZM2vJjmwA",
    "amr": ["pwd"],
    "app_displayname": "AzureAdTest",
    "appid": "A134d6c8-8078-2924-9e90-98cef862eb9a",
    "appidacr": "0",
    "family_name": "Bob",
    "given_name": "Bob",
    "ipaddr": "111.111.124.18",
    "name": "Bob Powell",
    "oid": "5b2dfaea-41fb-4a76-93da-6b4c04041f4d",
    "platf": "3",
    "puid": "10032000A35A0EE1",
    "scp": "openid profile User.Read email",
    "sub": "NM4nVqUfyC-6pF66I1Wef8Bvl7rhnpB_UBv7fX-qMHU",
    "tid": "abc60396-1ed0-4fa3-a3d0-597adf1366a5",
    "unique_name": "[email protected]",
    "upn": "[email protected]",
    "uti": "-mwXtFoS1kGJjorQqzI0AA",
    "ver": "1.0",
    "xms_st": {
        "sub": "p7nf6_rRkoqINUHy3cl_qRQ2F-DaCfFwQgy6gTQv_QY"
    },
    "xms_tcdt": 1583932579
}
'.

My previous question was:

I believe I have the Microsoft Authentication Library (MSAL) JavaScript pulling back a JWT token, using azure AD multi tenant with the following config. Based of this link https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant. I believe I only need the following two values.

clientId: "A134d6c8-8078-2924-9e90-98cef862eb9a" // this would be the app registrations client id(application)
authority: "https://login.microsoftonline.com/common"

How then can I configure a .net core 3 web api that can handle this JWT token and authenticate [Authorize] endpoints by me passing the Authorization: Bearer header.

I currently get this error in the response which is not very helpful!

AuthenticationFailed: IDX10511: Signature validation failed. Keys tried: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. 
kid: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. 
Exceptions caught:
 '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
token: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.

The Startup.cs code is as follows

using System.Text;
using System.Threading.Tasks;
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.IdentityModel.Tokens;

namespace MultiTenantApi
{
    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.AddCors(x =>
            {
                x.AddDefaultPolicy(cfg =>
                {
                    cfg.AllowAnyOrigin()
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                });
            });

            services.AddAuthentication(cfg =>
                {
                    cfg.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(opt =>
                {
                    opt.Authority = "https://login.microsoftonline.com/common";
                    opt.Audience = "api://A134d6c8-8078-2924-9e90-98cef862eb9a"; // Set this to the App ID URL for the web API, which you created when you registered the web API with Azure AD.
                    opt.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false
                    };
                    opt.Events = new JwtBearerEvents()
                    {
                        OnAuthenticationFailed = AuthenticationFailed
                    };
                });

            services.AddControllers();

        }

        private Task AuthenticationFailed(AuthenticationFailedContext arg)
        {
            // For debugging purposes only!
            var s = $"AuthenticationFailed: {arg.Exception.Message}";
            arg.Response.ContentLength = s.Length;
            arg.Response.Body.WriteAsync(Encoding.UTF8.GetBytes(s), 0, s.Length);
            return Task.FromResult(0);
        }
        // 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(); // Added

            app.UseRouting();
            app.UseCors(); //Added

            app.UseAuthentication();
            app.UseAuthorization();

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

        }

    }
}
like image 694
Andrew Avatar asked Mar 17 '20 11:03

Andrew


People also ask

Does Azure AD use JWT?

Token types. Azure AD B2C supports the OAuth 2.0 and OpenID Connect protocols, which makes use of tokens for authentication and secure access to resources. All tokens used in Azure AD B2C are JSON web tokens (JWTs) that contain assertions of information about the bearer and the subject of the token.

Can Azure AD have multiple tenants?

Azure AD B2B collaboration enables users to use one set of credentials to sign in to multiple tenants. For educational institutions, the benefits of B2B collaboration include: Centralized administration team managing multiple tenants.


1 Answers

With the help of juunas response above, I change my scope from user.read to the following this is my client id(application id) followed by .default

var tokenRequest = {
    scopes: ["A134d6c8-8078-2924-9e90-98cef862eb9a/.default"]
};
await this.app.acquireTokenSilent(tokenRequest)
   ... etc

After this I could see aud value was no longer the graph api one

"aud": "A134d6c8-8078-2924-9e90-98cef862eb9"

In the C# API my code now works with this in the ConfigureServices Startup.cs file

services.AddAuthentication(cfg =>
{
    cfg.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(opt =>
{
    opt.Authority = "https://login.microsoftonline.com/common";
    opt.Audience = "api://A134d6c8-8078-2924-9e90-98cef862eb9a"; // Set this to the App ID URL for the web API, which you created when you registered the web API with Azure AD.

    opt.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true, 
        ValidateAudience = true, 
        ValidAudiences = new List<String>
        {
            // you could add a list of valid audiences
            "A134d6c8-8078-2924-9e90-98cef862eb9a"
        }, 
        ValidIssuers = new List<string>
        {
            // Add tenant id after https://sts.windows.net/
            "https://sts.windows.net/{YourTenantId}"
        }
    };
    opt.Events = new JwtBearerEvents()
    {
        OnAuthenticationFailed = AuthenticationFailed
    };
});
like image 200
Andrew Avatar answered Oct 23 '22 04:10

Andrew