rj2700
rj2700

Reputation: 1965

Azure B2C - Accept query params into OAuth2 JWT

I was curious if it was possible to read query parameters when requesting an OAuth2 token through Azure?

Essentially, when making a test call with a policy that I created, I would like to have an additional query parameters read from the call and the orchestration (user journey) steps should read these values and inject that value into a custom claim (for the JWT or ID token).

I know from the follow links that it may* be possible with Azure B2C service? But I can't find any good concrete examples.

Sign-up policy - Set user attributes through code

Add Custom Attribute Not Used in Sign-Up nor Edit Policy

How can I return the PolicyId Claim after executing my Custom SignUpSignIn policy?

How do i include email in the redirect to AZURE AD B2C

I then proceeded in trying a bunch of configurations out but there are so many options to choose from, I don't know which to choose. In addition, I haven't been able to find any Azure docs that describe the options used when configuring these policies. In any case, here is what I have.

I downloaded the TrustFrameworkBase.xml and TrustFrameworkExtensions.xml from here. I got this Github link from this Azure doc, which I also followed the steps on setting up policy keys and added an app registration with delegated permissions. For my relying party configuration, I simply made a custom policy through the Azure B2C portal and downloaded it as a starting point to explore what it looks like in a basic form.

Here is my custom claim added to the base policy within the ClaimsSchema tag. extension_Test is the claim where I want to inject the value from a query param:

  <ClaimType Id="extension_Test">
    <DisplayName>Test value</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="extension_Test" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="extension_Test" />
    </DefaultPartnerClaimTypes>
    <UserInputType>Readonly</UserInputType>
  </ClaimType>
</ClaimsSchema>

In the same base policy, here's the userjourney that I added for SignIn:

<UserJourney Id="SignIn">
        <OrchestrationSteps>
            <OrchestrationSteps>
            <!-- The following orchestration step is always executed. -->
            <OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselection.signupsignin">
                <ClaimsProviderSelections>
                    <ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountRegistrationExchange" />
                </ClaimsProviderSelections>
            </OrchestrationStep>
            <OrchestrationStep Order="2" Type="ClaimsExchange">
              <ClaimsExchanges>
                <ClaimsExchange Id="LocalAccountRegistrationExchange" TechnicalProfileReferenceId="LocalAccount-Registration-VerifiedEmail" />
              </ClaimsExchanges>
            </OrchestrationStep>
            <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
        </OrchestrationSteps>

    </UserJourney>

Here's my relying config XML:

 <RelyingParty>
    <DefaultUserJourney ReferenceId="SignIn" />
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="extension_Test" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="surname" />
        <OutputClaim ClaimTypeReferenceId="extension_Test" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>

I think uploaded the base, extensions and RP policies XML files in that order. The GET request that I'm sending looking like this (got from the "Run now" button for the custom policy):

https://login.microsoftonline.com/<TENANT>/oauth2/v2.0/authorize?p=B2C_1A_test&client_id=<TENANTID>&nonce=defaultNonce&redirect_uri=http%3A%2F%2Flocalhost%2Fredirect&scope=openid&response_type=id_token&prompt=login&extension_Test=aaa

Any help would be greatly appreciated, thanks! Or Azure documents that explain more options within these config files - as in what does CpimIssuerTechnicalProfileReferenceId="JwtIssuer" mean? Or AzureFunction-WrapWebHook mean?

Upvotes: 4

Views: 1740

Answers (1)

Chris Padgett
Chris Padgett

Reputation: 14654

You are close.

An end-to-end example of inputting a claim to a journey, and then using it in this journey (e.g. pre-conditions or storage) as well as outputting it from the journey, can be found in this "Implementing an invitation flow" document (which I was author of).

The high-level solution is:

1) At design-time, configure the relying party policy with the input claim.

<RelyingParty>
  <DefaultUserJourney ReferenceId="SignIn" />
  <TechnicalProfile Id="PolicyProfile">
    <DisplayName>PolicyProfile</DisplayName>
    <Protocol Name="OpenIdConnect" />
    <InputTokenFormat>JWT</InputTokenFormat>
    <CryptographicKeys>
      <Key Id="client_secret" StorageReferenceId="B2C_1A_MySharedSecret" />
    </CryptographicKeys>
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="extension_Test" />
    </InputClaims>
    <OutputClaims>
      ...
      <OutputClaim ClaimTypeReferenceId="extension_Test" />
    </OutputClaims>
    <SubjectNamingInfo ClaimType="sub" />
  </TechnicalProfile>
</RelyingParty>

You must create a policy key (in the above example, this is called "MySharedSecret", but it can be called anything) containing a shared secret that is known to the application that is invoking this policy (where the client secret for this application can be this shared secret).

2) At runtime, create a self-issued JWT containing the input claim, sign this JWT with the shared secret, and then add the JWT to the authentication request using the "client_assertion_type" and "client_assertion" parameters.

The code example for this can be found in the Wingtip sample.

An example of the authentication request is:

https://login.microsoftonline.com/b2ctechready.onmicrosoft.com/oauth2/v2.0/authorize?p=b2c_1a_invitation&...&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJhbGci...7m9s&state=CfDJ8EPk...Et0w

Upvotes: 5

Related Questions