I am trying to use a client credential (ie client_id & client_secret) to access a custom policy (for Azure AD B2C) to get a custom JWT back. I can do this now (see here: OIDC-Connect technical profile only works under a self-asserted validation reference (but need it not to require a self-asserted profile)) however I can't work out how to pass a query parameter through that is recognized in the custom policy.
This is my custom policy: MyPolicy.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="{tenant}.onmicrosoft.com"
PolicyId="B2C_1A_MyPolicy"
PublicPolicyUri="http://{tenant}.onmicrosoft.com/B2C_1A_MyPolicy"
DeploymentMode="Development"
UserJourneyRecorderEndpoint="urn:journeyrecorder:applicationinsights">
<BasePolicy>
<TenantId>{tenant}.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
</BasePolicy>
<BuildingBlocks>
<ClaimsSchema>
<!-- JWT -->
<ClaimType Id="value">
<DataType>string</DataType>
</ClaimType>
</ClaimsSchema>
</BuildingBlocks>
<ClaimsProviders>
<ClaimsProvider>
<DisplayName></DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SetQueryParams">
<DisplayName>Set the BrandId and other query params from the OIDC:ClientId field in the url params</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="value" DefaultValue="{OAUTH-KV:value}" AlwaysUseDefaultValue="true" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<UserJourneys>
<UserJourney Id="MyUserJourney">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SetQueryParamsStep" TechnicalProfileReferenceId="SetQueryParams" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Issue JWT -->
<OrchestrationStep Order="2" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
</UserJourney>
</UserJourneys>
<RelyingParty>
<DefaultUserJourney ReferenceId="MyUserJourney" />
<UserJourneyBehaviors>
<JourneyInsights TelemetryEngine="ApplicationInsights" InstrumentationKey="623badc9-900b-44e3-bd44-bf00d97d9d93" DeveloperMode="true" ClientEnabled="true" ServerEnabled="true" TelemetryVersion="1.0.0" />
<ScriptExecution>Allow</ScriptExecution>
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" AlwaysUseDefaultValue="true" DefaultValue="8186c7b3-adca-4c17-b318-939e9d8170b8" />
<OutputClaim ClaimTypeReferenceId="value" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>
And am calling it with this:
(x-www-form-urlencoded) https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/B2C_1A_MyPolicy/oauth2/v2.0/token?grant_type=client_credentials&client_id=&client_secret=<client_secret>&scope=https://{tenant}.onmicrosoft.com/api/.default
Which executes the custom policy as I expect; it returns a JWT and it shows fields that I add in there with hardcoded defaults (such as: DefaultValue="8186c7b3-adca-4c17-b318-939e9d8170b8" in the RelyingParty)
This gets more interesting if I change the RelyingParty to have the DefaultValue="{OAUTH-KV:value}"
as shown below:
<RelyingParty>
<DefaultUserJourney ReferenceId="MyUserJourney" />
<UserJourneyBehaviors>
<JourneyInsights TelemetryEngine="ApplicationInsights" InstrumentationKey="{Settings:AppInsightsKey}" DeveloperMode="true" ClientEnabled="true" ServerEnabled="true" TelemetryVersion="1.0.0" />
<ScriptExecution>Allow</ScriptExecution>
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" AlwaysUseDefaultValue="true" DefaultValue="8186c7b3-adca-4c17-b318-939e9d8170b8" />
<OutputClaim ClaimTypeReferenceId="value" DefaultValue="{OAUTH-KV:value}" AlwaysUseDefaultValue="true" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
Which then returns the following:
{
"error": "invalid_grant",
"error_description": "AADB2C90085: The service has encountered an internal error. Please reauthenticate and try again.\r\nCorrelation ID: 1c7b50fa-87bb-4588-8ec0-90e8ed3554be\r\nTimestamp: 2022-12-18 22:05:45Z\r\n"
}
I just want to give client credentials for authentication and supplement them with inputs that I have; I imagine I must be doing something silly as this seems like it should be fairly straight foward.