|
| 1 | +--- |
| 2 | +title: Troubleshoot IDX10501 Error in ASP.NET Core with Azure B2C Custom Policy |
| 3 | +description: Provides guidance for troubleshooting IDX10501 Error in ASP.NET Core with Azure B2C. |
| 4 | +ms.date: 01/06/2025 |
| 5 | +ms.author: bachoang |
| 6 | +ms.service: entra-id |
| 7 | +ms.custom: sap:Microsoft Entra App Integration and Development |
| 8 | +--- |
| 9 | + |
| 10 | +# Resolving IDX10501 Error in ASP.NET Core with Azure B2C Custom Policy |
| 11 | + |
| 12 | +This guide will help you understand the cause of the IDX10501 error and provide a step-by-step solution to resolve it. |
| 13 | + |
| 14 | +## Symptoms |
| 15 | +When you [implement a custom policy](/azure/active-directory-b2c/enable-authentication-web-application-options#pass-the-azure-ad-b2c-policy-id) in an ASP.NET Core application that integrates with Azure Active Directory B2C (Azure AD B2C), you may encounter the following IDX10501 error: |
| 16 | + |
| 17 | +> IDX10501: Signature validation failed. Unable to match key: kid: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. Number of keys in TokenValidationParameters: '0'. Number of keys in Configuration: '1'. Exceptions caught: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. token: '[PII of type 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. |
| 18 | +
|
| 19 | +## Understanding the Error |
| 20 | + |
| 21 | +First, let’s understand why this error is being thrown when the custom policy redirects back to your app. In ASP.NET Core, whenever a user is authenticated and authorized, and there is a redirect back to the Web app that contains an ID Token.The ASP.NET Core middleware will try to validate this ID Token to make sure that the redirect is genuine. To validate the ID Token, the Middleware needs the public key of the signing certificate which was used to sign the ID Token. The Middleware gets this public key by querying AAD B2C. Specifically, there is a "metadata" endpoint in AAD B2C used by the Middleware which provides authentication information including any public keys for signing certificates. |
| 22 | + |
| 23 | +When you created your custom policy, you was required to create or upload a signing certificate. This signing certificate is different from that used for built-in user flows in AAD B2C. This means that the public keys accessible from the "metadata" endpoint for your AAD B2C will not contain the public key for your custom policy. The custom policy actually has it’s own metadata endpoint. |
| 24 | + |
| 25 | +The endpoint which the Middleware uses is configured by Microsoft.Identity.Web and set at app startup. Since the metadata URL is already set, invoking a custom policy during runtime will result in a scenario where the Middleware is looking at the wrong metadata URL while validating the returning token. |
| 26 | + |
| 27 | +## Solution |
| 28 | + |
| 29 | +To resolve this issue, you must configure configure the correct metadata endpoint for the additional Custom Policy. To do this, create a second authentication scheme to handle the custom policy. With this additional authentication scheme, we can set the correct metadata endpoint at startup. Below is a brief overview of the steps involved: |
| 30 | + |
| 31 | +1. Add an additional redirect URI to your App Registration. |
| 32 | +2. Configure an additional B2C authentication scheme in your app. |
| 33 | +3. Add an action to the desired controller. |
| 34 | +4. Implement the created action in the Layout. |
| 35 | + |
| 36 | +Code sample: [Github project: ASP.NET Core Web App with Custom B2C Policy](https://github.com/mbukovich/ExtraB2CPolicyMVC). |
| 37 | + |
| 38 | +### Prerequisites |
| 39 | + |
| 40 | +Before continuing, Ensure you have: |
| 41 | + |
| 42 | +- An Azure B2C directory |
| 43 | +- An app registration for B2C authentication |
| 44 | +- [Standard user flows set up](/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-user-flow) |
| 45 | +- [A custom B2C policy added to your directory](/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-custom-policy) |
| 46 | +- An existing ASP.NET Core web app configured with Microsoft.Identity.Web for B2C authentication. For more information, see [Enable authentication in your own web app by using Azure AD B2C](/azure/active-directory-b2c/enable-authentication-web-application?tabs=visual-studio) |
| 47 | + |
| 48 | +### Step 1: Add an Additional Redirect URI |
| 49 | + |
| 50 | +In your the App Registration, you need to add another redirect URI for the custom policy. The reason you cannot use the existing redirect URI in this case is that it could cause confusion for the Web App. We will set up two different authentication schemes, but when the B2C policy redirects back to the Web App, the Middleware will not know which authentication scheme to use. Thus, we need a separate redirect URI to clearly distinguish redirects from the existing and new authentication schemes. |
| 51 | + |
| 52 | +1. Navigate to your app registration in the [Azure Portal](https://portal.azure.com). |
| 53 | +2. In the **Manage** section, select **Authentication**. |
| 54 | +3. In the **Redirect URIs** section, select **Add URI**. |
| 55 | +4. Add a new redirect URI. In this article, the new redirect URI is `https://localhost:44321/signin-oidc-editemail`. |
| 56 | + |
| 57 | +> [!NOTE] |
| 58 | +> Each custom policy requires its own redirect URI. For example, if you're adding two custom policies, you will need to create two authentication scheme and two redirect URIs. |
| 59 | +
|
| 60 | +### Step 2: Configure an Additional Authentication Scheme |
| 61 | + |
| 62 | +This process involves adding an action to your controller that will issue a challenge to the user. Before creating this action, we need to configure the app with an additional authentication scheme. This requires updating both the appsettings.json file and the Startup.cs file. |
| 63 | + |
| 64 | +#### Update `appsettings.json` |
| 65 | + |
| 66 | +Add the following configuration for your custom policy: |
| 67 | + |
| 68 | +```json |
| 69 | +"<name-of-your-configuration>": { |
| 70 | + "Instance": "https://<B2C-tenant-name>.b2clogin.com", |
| 71 | + "ClientId": "<client-id-of-your-app-registration>", |
| 72 | + "CallbackPath": "/<endpoint-of-your-new-redirect-uri>", |
| 73 | + "SignedOutCallbackPath": "/signout/<built-in-sign-in-sign-up-policy>", |
| 74 | + "Domain": "<B2C-tenant-name>.onmicrosoft.com", |
| 75 | + "SignUpSignInPolicyId": "<built-in-sign-in-sign-up-policy>" |
| 76 | +}, |
| 77 | +``` |
| 78 | + |
| 79 | +Example of the `appsettings.json` |
| 80 | + |
| 81 | +```json |
| 82 | +{ |
| 83 | + "AzureADB2C": { |
| 84 | + "Instance": "https://markstestorganization1.b2clogin.com", |
| 85 | + "ClientId": "09717d12-ca7f-4388-8393-dafe42c0c3a5", |
| 86 | + "CallbackPath": "/signin-oidc", |
| 87 | + "SignedOutCallbackPath": "/signout/B2C_1_signupsignin1", |
| 88 | + "Domain": "markstestorganization1.onmicrosoft.com", |
| 89 | + "SignUpSignInPolicyId": "B2C_1_signupsignin1", |
| 90 | + "ResetPasswordPolicyId": "B2C_1_PasswordReset1", |
| 91 | + "EditProfilePolicyId": "B2C_1_editProfileTest1" |
| 92 | + }, |
| 93 | + "AzureADB2CEditEmail": { |
| 94 | + "Instance": "https://markstestorganization1.b2clogin.com", |
| 95 | + "ClientId": "09717d12-ca7f-4388-8393-dafe42c0c3a5", |
| 96 | + "CallbackPath": "/signin-oidc-editemail", |
| 97 | + "SignedOutCallbackPath": "/signout/B2C_1_signupsignin1", |
| 98 | + "Domain": "markstestorganization1.onmicrosoft.com", |
| 99 | + "SignUpSignInPolicyId": "B2C_1_signupsignin1" |
| 100 | + }, |
| 101 | + "Logging": { |
| 102 | + "LogLevel": { |
| 103 | + "Default": "Information", |
| 104 | + "Microsoft": "Warning", |
| 105 | + "Microsoft.Hosting.Lifetime": "Information" |
| 106 | + } |
| 107 | + }, |
| 108 | + "AllowedHosts": "*" |
| 109 | +} |
| 110 | +``` |
| 111 | +**Important Considerations** |
| 112 | + |
| 113 | +- You can choose any name for the second B2C configuration. This configuration will be used for a single custom policy. If you need to add more custom policies, you'll have to include additional B2C configurations in the AppSettings.json file. For this reason, it's recommended to give the JSON object a name that reflects the associated custom policy. |
| 114 | +- The CallbackPath is the portion of the Redirect URI that follows the domain. For example, if your redirect URI is `https://localhost:44321/signin-oidc-editemail`, then the CallbackPath will be `/signin-oidc-editemail`. |
| 115 | +- You need to include the standard built-in sign-up/sign-in user flow in the authentication scheme to ensure that users are prompted to sign in if they try to access your custom policy without signed-in. |
| 116 | + |
| 117 | +#### Update `Startup.cs` |
| 118 | + |
| 119 | +Configure an additional authentication scheme in the startup.cs file. In the `ConfigureServices` function, add the following code: |
| 120 | + |
| 121 | + |
| 122 | +```csharp |
| 123 | +// Create another authentication scheme to handle extra custom policy |
| 124 | +services.AddAuthentication() |
| 125 | + .AddMicrosoftIdentityWebApp(Configuration.GetSection("<name-of-json-configuration>"), "<Arbitrary-name-for-Auth-Scheme>", "<Arbitrary-name-of-Cookie-Scheme>"); |
| 126 | + |
| 127 | +services.Configure<OpenIdConnectOptions>("<Arbitrary-name-for-Auth-Scheme>", options => |
| 128 | + { |
| 129 | + options.MetadataAddress = "<Metadata-Address-for-Custom-Policy>"; |
| 130 | + }); |
| 131 | +``` |
| 132 | + |
| 133 | +- You will need to set custom names for both your authentication scheme and the associated cookie scheme. Microsoft.Identity.Web will create these schemes using the names you specify. |
| 134 | + |
| 135 | +- Additionally, replace `<name-of-json-configuration>` with the name of the JSON configuration from the previous step. In the example of this article, it should be `AzureADB2CEditEmail`. |
| 136 | + |
| 137 | +- Replace `<Your-Custom-Metadata-URL>` with the OpenID Connect discovery endpoint URL found under your custom policy in Azure AD B2C. |
| 138 | + |
| 139 | +### Step 3: Add Action to Controller |
| 140 | + |
| 141 | +In your controller (e.g., HomeController), add this action method: |
| 142 | + |
| 143 | +```csharp |
| 144 | +[Authorize] |
| 145 | +public IActionResult EditEmail() |
| 146 | +{ |
| 147 | + var redirectUrl = Url.Content("~/"); |
| 148 | + var properties = new AuthenticationProperties { RedirectUri = redirectUrl }; |
| 149 | + properties.Items["policy"] = "<Your-Custom-Policy>"; |
| 150 | + |
| 151 | + return Challenge(properties, "<CustomAuthScheme>"); |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | +Ensure `<Your-Custom-Policy>` matches your specific policy name and `<CustomAuthScheme>` is consistent with what you configured earlier. |
| 156 | + |
| 157 | +### Step 4: Implement Action in Layout |
| 158 | + |
| 159 | +Add UI elements to invoke the action that triggers your custom policy: |
| 160 | + |
| 161 | +```html |
| 162 | +<li class="navbar-btn"> |
| 163 | + <form method="get" asp-area="" asp-controller="Home" asp-action="EditEmail"> |
| 164 | + <button type="submit" class="btn btn-primary">Edit Email</button> |
| 165 | + </form> |
| 166 | +</li> |
| 167 | +``` |
| 168 | + |
| 169 | +This snippet should be placed where appropriate within your app's layout or navigation structure. |
| 170 | + |
| 171 | +By following these steps meticulously, you can successfully implement a custom authentication scheme within your ASP.NET Core app utilizing Azure AD B2C and resolve any related IDX10501 errors experienced during token validation. |
| 172 | +[!INCLUDE [Azure Help Support](../../../includes/azure-help-support.md)] |
0 commit comments