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:
/authorize
URL includes extension_inviteToken=...
and the audit log confirms it is present.<InputClaims>
<InputClaim ClaimTypeReferenceId="extension_inviteToken" />
</InputClaims>
{ "InviteToken": "..." }
and works with Postman.{}
or { "InviteToken": null }
from B2C.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.
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.