Home > Software design >  How to validate an Azure B2C JWT token in a web API?
How to validate an Azure B2C JWT token in a web API?

Time:09-23

Literally as per the title, I can get a token from Azure B2C via my web client, now all I need to do is validate that in my API.

This is my appsettings.json (details changed but the numbered GUIDs shown match each other in the real file):

{
  "AzureAdB2C": {
    "Authority": "https://login.mydomain.net/00000000-0000-0000-0000-000000000000",
    "Audience": "11111111-1111-1111-1111-111111111111",
    "Instance": "https://login.mydomain.net",
    "Domain": "mydomain.net",
    "ClientId": "11111111-1111-1111-1111-111111111111",
    "TenantId": "00000000-0000-0000-0000-000000000000"
  },
  "ConnectionStrings": {
    "SQLConnection": "Data Source=MyAppDebug.db;Cache=Shared"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

And I've tried these in my Startup.cs:

// Throws "System.InvalidOperationException: No authenticationScheme was specified, and
// there was no DefaultChallengeScheme found."
services.AddAuthentication()
                .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAdB2C"));
// Throws "System.InvalidOperationException: IDX20803: Unable to obtain configuration
// from: 'System.String'."
services.AddMicrosoftIdentityWebApiAuthentication(Configuration, Constants.AzureAdB2C);
// Throws "System.InvalidOperationException: IDX20803: Unable to obtain configuration
// from: 'System.String'."
services.AddAuthentication(options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.Audience = Configuration["AzureAdB2C:Audience"];
                options.Authority = Configuration["AzureAdB2C:Authority"];
            });
// Throws "System.InvalidOperationException: IDX20803: Unable to obtain configuration
// from: 'System.String'."
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApi(
                    (jwtOptions) =>
                    {
                        // I've commented this out because I don't yet have roles set up in
                        // Azure, but I have to include something for jwtOptions otherwise
                        // it won't build.
                        //// jwtOptions.TokenValidationParameters.RoleClaimType = "groups";
                    },
                    (options) =>
                    {
                        options.ClientId = this.Configuration["AzureAdB2C:ClientId"];
                        options.TenantId = this.Configuration["AzureAdB2C:TenantId"];
                        options.Domain = this.Configuration["AzureAdB2C:Domain"];
                        options.Instance = this.Configuration["AzureAdB2C:Instance"];
                    });

I'm at my wits end and can't understand how this is so difficult. Microsoft guides and documentation, as usual, are nothing short of useless.

I have a valid JWT token, all I want to do is validate it's signature, audience, issuer and claims. So far it's taken longer to try and validate this token than it did to set up the B2C directory, register for a Google dev account and obtain credentials to add to Azure, register my applications, add my own custom scope, create client secrets, implement into my web app and sign up new users.

CodePudding user response:

I wrote this a while back in the context of ADFS but the principles are the same.

B2C also has a well-known endpoint that you can use to check the signature.

Also, for .NET Core.

And a ton of libraries here.

CodePudding user response:

I eventually found out that I (or rather, the API) was not constructing the URL of the issuer properly, it needs to include the policy used to create the token (Sign Up/Sign In policy).

This is what I needed in the appsettings.json file:

"AzureAdB2C": {
    "Instance": "https://login.mydomain.net",
    "ClientId": "00000000-0000-0000-0000-000000000000",
    "TenantId": "11111111-1111-1111-1111-111111111111",
    "SignUpSignInPolicyId": "B2C_1_SignUpIn"
  }

And this is the code I used in Startup.cs:

services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; })
    .AddJwtBearer(jwtOptions =>
        {
            jwtOptions.Authority =
                $"{Configuration["AzureAdB2C:Instance"]}/{Configuration["AzureAdB2C:TenantId"]}/{Configuration["AzureAdB2C:SignUpSignInPolicyId"]}/v2.0/";
            jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
        });

That being said, the exception type and message I was getting is extremely unhelpful.

  • Related