asp.net-coreazure-ad-b2cazure-ad-b2c-custom-policy

Azure AD B2C Custom Policy: extension_inviteToken Not Passed to REST API Despite Correct Mapping


I am experiencing an issue with my Azure AD B2C custom policy where the extension_inviteToken claim, although present in the /authorize URL and audit logs, is not being passed to my REST API technical profile. The API receives an empty or null value for InviteToken.

I have implemented the following, following all best practices:

<ClaimType Id="extension_inviteToken">
  <DisplayName>Invite Token</DisplayName>
  <DataType>string</DataType>
  <DefaultPartnerClaimTypes>
    <Protocol Name="OAuth2" PartnerClaimType="extension_inviteToken" />
  </DefaultPartnerClaimTypes>
</ClaimType>
<TechnicalProfile Id="REST-GetEmailFromInviteToken">
  <DisplayName>Get Email From Invite Token</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="ServiceUrl">https://api7502.ngrok.io/api/invite/validate</Item>
    <Item Key="SendClaimsIn">Body</Item>
    <Item Key="AuthenticationType">None</Item>
    <Item Key="AllowInsecureAuthInProduction">true</Item>
    <Item Key="DefaultUserMessageIfRequestFailed">Invite token missing or invalid.</Item>
  </Metadata>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="extension_inviteToken" PartnerClaimType="InviteToken" Required="true" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="email" />
    <OutputClaim ClaimTypeReferenceId="extension_accountName" />
    <OutputClaim ClaimTypeReferenceId="extension_contactName" />
    <OutputClaim ClaimTypeReferenceId="extension_inviteToken" />
  </OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="SelfAsserted-DebugInviteToken">
  <DisplayName>Debug Invite Token</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider" />
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="extension_inviteToken" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="extension_inviteToken" />
  </OutputClaims>
</TechnicalProfile>

And in the journey:

<OrchestrationStep Order="2" Type="ClaimsExchange">
  <ClaimsExchanges>
    <ClaimsExchange Id="DebugInviteToken" TechnicalProfileReferenceId="SelfAsserted-DebugInviteToken" />
  </ClaimsExchanges>
</OrchestrationStep>

Additional details:

Request:
Please help identify why the extension_inviteToken claim is not being passed from the OIDC request to the REST API, despite all mappings and best practices being followed.


Solution

  • If your invitation token is being passed in the query string of the authorize request then I'd recommend using a claims resolver to read the query string paramter directly in your API technical profile.

    For example:

    <TechnicalProfile Id="REST-GetEmailFromInviteToken">
      <DisplayName>Get Email From Invite Token</DisplayName>
      <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <Metadata>
        <Item Key="ServiceUrl">https://api7502.ngrok.io/api/invite/validate</Item>
        <Item Key="SendClaimsIn">Body</Item>
        <Item Key="AuthenticationType">None</Item>
        <Item Key="AllowInsecureAuthInProduction">true</Item>
        <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
        <Item Key="DefaultUserMessageIfRequestFailed">Invite token missing or invalid.</Item>
      </Metadata>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="extension_inviteToken" PartnerClaimType="InviteToken" DefaultValue="{OAUTH-KV:extension_inviteToken}" AlwaysUseDefaultValue="true" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="email" />
        <OutputClaim ClaimTypeReferenceId="extension_accountName" />
        <OutputClaim ClaimTypeReferenceId="extension_contactName" />
        <OutputClaim ClaimTypeReferenceId="extension_inviteToken" />
      </OutputClaims>
    </TechnicalProfile>
    

    That approach doesn't require you to configure any input claims in your relying party technical profile, it will just work if the query string parameter is populated.