An Azure service that provides a hybrid, multi-cloud management platform for APIs.
Q1. The approach is right. validate-jwt is the correct policy, since validate-azure-ad-token covers Microsoft Entra only, not B2C. Two corrections to the guide you linked.
You don't need custom policies. You've linked the custom policy pivot, which pulls in the Identity Experience Framework. The same page says:
"There are no specific actions to enable the client credentials for user flows or custom policies. Both Azure AD B2C user flows and custom policies support the client credentials flow."
Custom policies only matter at Step 4, if you want to inject extra claims into the token.
Second, the feature is still in public preview. Worth putting in front of whoever signs off the design.
Your instinct on scopes works cleanly. App roles defined with allowedMemberTypes: ["Application"] come back in the scp claim, so you can gate on them with required-claims.
Q2. No, because B2C already publishes it. Every user flow exposes an OpenID Connect metadata document at:
https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<policy>/v2.0/.well-known/openid-configuration
It's unauthenticated and already contains the token endpoint and your signing keys. Documenting it saves your customers a lookup. The credential is the client secret.
Q3. You're right that it's manual, and the reason sits in the flow itself:
"In the client credentials flow, permissions are granted directly to the application itself by an administrator."
Step 2.2 ends with Grant admin consent for your tenant, inside your B2C tenant, once per customer app. APIM subscription approval doesn't reach into B2C, and I can't find anything Microsoft ships that connects the two. If you want to keep self service, the only route I see is calling Microsoft Graph from your approval step to create the registration, assign the app role and grant consent.
A few details on the policy config
Roughly what the policy should look like:
xml
<validate-jwt header-name="Authorization" failed-validation-httpcode="401">
<openid-config url="https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/<policy>/v2.0/.well-known/openid-configuration"
validate-connectivity="false" />
<audiences>
<audience>{client ID of your API app registration}</audience>
</audiences>
<required-claims>
<claim name="scp" match="any">
<value>app.read</value>
</claim>
</required-claims>
</validate-jwt>
validate-connectivity="false" if your APIM is in a VNet. Given the Application Gateway in front, this probably applies to you. From the policy reference:
"If the API Management instance is injected or integrated in a virtual network and
openid-configendpoint URLs are configured in the policy, set thevalidate-connectivityattribute tofalseto disable check of endpoint availability."
Leave it out and the policy fails a reachability check that has nothing to do with whether your tokens are valid.
Point openid-config at your b2clogin.com metadata document. The B2C example on that policy page still uses login.microsoftonline.com/tfp/..., which is the legacy host. Match the host you actually request tokens from.
The audience is the client ID of the API app registration, not the Application ID URI. The URI is what goes in the scope parameter of the token request. Two different values for what looks like the same thing.
Set accessTokenAcceptedVersion to 2 in the manifest if you reuse an existing app registration rather than creating a fresh one.
One last thing if this is a new tenant: B2C closed to new customers on 1 May 2025. Existing tenants carry on.
Help make this community better for everyone: if this answer resolved your issue, please accept it or leave an upvote. If not, share more details in a comment so we can continue the discussion and find the right solution.