0

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.

Dessus
  • 2,147
  • 1
  • 14
  • 24

1 Answers1

1

Policy looks good in the first half of the question. Call it with 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&value=foo

Jas Suri - MSFT
  • 10,605
  • 2
  • 10
  • 20
  • How do I ensure the client_secret is legit? I have noticed its entirely optional to provide as a query parameter which is worrying. I had tried the client credentials sample in the b2c samples repo but that also allows without checking the client secret. – Dessus Dec 19 '22 at 02:25
  • 1
    If your app registration is setup as a Web App, the client secret is enforced. And executing your policy in the endpoint (b2c_1A_mypolicy) is an endpoint that is enforcing the check. Also you cannot use that scope. You cannot use any scope pertaining to a Microsoft service. – Jas Suri - MSFT Dec 20 '22 at 09:26
  • Were you able to get around this issue? and get ahold of the 'value' value using {OAUTH-KV:value} ? I am having the exact same problem – Juan P. Garces Aug 21 '23 at 13:00