Reputation: 491
In my solution I have Azure AD B2C and recently I added Azure Front Door to allow users to access Azure AD B2C via a custom domain. (see https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-domain?pivots=b2c-custom-policy)
Users of my application can now obtain a JWT token from Azure AD B2C using either the original B2C domain URL, or the custom domain (via Azure Front Door).
I can successfully create a valid JWT token using both domains, and when I compare them the only difference is the iss
value.
When using the original Azure AD B2C domain name (domain and tenant names are redacted):
"iss": "https://myappname.b2clogin.com/myappname.onmicrosoft.com/v2.0/"
When using the custom domain via Azure Front Door:
"iss": "https://login.myappname.nl/00000000-0000-0000-0000-000000000000/v2.0/"
This means I have 2 distinct addresses for my Open ID Connect well known config:
https://myappname.b2clogin.com/myappname.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1A_MYAPPVERIFICATIONANDSIGNUP
https://login.myappname.nl/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration?p=B2C_1A_MYAPPVERIFICATIONANDSIGNUP
In Azure API Management I have setup a policy to validate the JWT token. With the introduction of the custom domain I now need to support both tokens.
<policies>
<inbound>
<set-variable name="iss" value="@(context.Request.Headers.GetValueOrDefault("Authorization", "")?.Split(' ')?.ElementAtOrDefault(1)?.AsJwt()?.Claims["iss"]?.FirstOrDefault() ?? "")" />
<choose>
<when condition="@(context.Variables.GetValueOrDefault("iss", "").StartsWith("https://login"))">
<validate-jwt header-name="Authorization">
<openid-config url="https://login.myappname.nl/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration?p=B2C_1A_MYAPPVERIFICATIONANDSIGNUP" />
<audiences>
<audience>[redacted_audience_id]</audience>
</audiences>
</validate-jwt>
</when>
<otherwise>
<validate-jwt header-name="Authorization">
<openid-config url="https://myappname.b2clogin.com/myappname.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1A_MYAPPVERIFICATIONANDSIGNUP" />
<audiences>
<audience>[redacted_audience_id]</audience>
</audiences>
</validate-jwt>
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
I first read the iss
value to determine the Open Id config URL to be used in the validate-jwt
element. If the iss
starts with https://login
I validate against the open-id config URL of the custom domain, otherwise I use the URL from the original B2C domain. Note: the audience is the same for both.
A call with a JWT token from the original B2C domain works and successfully passes the policy validation.
A call with a JWT token from the custom domain fails with a 401 error response.
When I look in Application Insights with the following query
// Last 100 failed requests
ApiManagementGatewayLogs
| where TimeGenerated > ago(1d)
| where IsRequestSuccess == false
| top 100 by TimeGenerated desc| where ResponseCode >= 400
I see my failed request with these error details:
Column | Value |
---|---|
LastErrorSource | validate-jwt |
LastErrorScope | product |
LastErrorSection | inbound |
LastErrorReason | TokenSignatureKeyNotFound |
LastErrorMessage | IDX10500: Signature validation failed. No security keys were provided to validate the signature. |
I am puzzled why the policy in Azure API Management accept a token from the original B2C domain but not the one from my custom domain.
Upvotes: 0
Views: 480
Reputation: 491
Many thank to the comment made by @VitaliyKurokhtin. Apparently <validate-jwt>
allows for multiple <openid-config>
elements, so instead of deciding what to do based on the iss
value I could simply add 2 openid-config urls and having just a single audience.
<policies>
<inbound>
<validate-jwt header-name="Authorization">
<openid-config url="https://login.myappname.nl/00000000-0000-0000-0000-000000000000/v2.0/.well-known/openid-configuration?p=B2C_1A_MYAPPVERIFICATIONANDSIGNUP" />
<openid-config url="https://myappname.b2clogin.com/myappname.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1A_MYAPPVERIFICATIONANDSIGNUP" />
<audiences>
<audience>[redacted_audience_id]</audience>
</audiences>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
Upvotes: 1