In Azure AD B2C custom policies, how do the IdentityExperienceFrameworkApps connect to AD without secrets - azure-ad-b2c

Also posted to https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/issues/29
In the B2C Custom Policy Starterpack we have the file LocalAccounts/TrustFrameworkExtensions.xml with:
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<Metadata>
<Item Key="client_id">ProxyIdentityExperienceFrameworkAppId</Item>
<Item Key="IdTokenAudience">IdentityExperienceFrameworkAppId</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFrameworkAppID" />
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFrameworkAppID" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
Can someone explain why two applications are required to make these custom policies work?
How does the IEF use each of them?
Besides, I don't see any secret or application key being passed to IEF in these files. How can IEF connect to AAD using Application Ids only?

The login-NonInteractive technical profile authenticates a local account by sending an access token request, using the resource owner password credentials grant type, to your Azure AD directory:
<Metadata>
<Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFrameworkAppID" />
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFrameworkAppID" />
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" Required="true" />
<InputClaim ClaimTypeReferenceId="password" Required="true" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
<InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />
</InputClaims>
Like all access token requests for an Azure AD directory, this access request must contain the identifier of a client application (i.e. the ProxyIdentityExperienceFramework application) and that of a resource application (i.e. the IdentityExperienceFramework application).
You don't have to specify a secret for the client application because it is registered as a native application.

Related

Azure AD B2C access claim/information from incoming login request

Currently, using B2C with custom policies having moved from Auth0. It was possible within Auth0 to access the scope claim/property of an incoming login request from the UI and then use that value within Rules to apply some logic. This doesn't seem to be easily do-able in B2C
My user journey allows a user to login using their Azure / Office 365 login via an AD Connector, then enrich the user's claim by calling one of my APIs to get more information about that user account before returning the updated claims to the UI. This all works fine.
What I want to do is expand the enrichment request to include the Audience value from the incoming login request. I have multiple front-end applications that use B2C and want different extra info included in the claims sent back to the UI so filtering on Client ID of the Azure AD APP used by the UI would be good. I would also like to see/access the Scope from the incoming login request as it has some information I would like send to the backend API.
I've tried the following but it doesn't like aud or audience as a claim name and scope is always null.
<TechnicalProfile Id="REST-API">
<DisplayName>Enrich User</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<!-- Set the ServiceUrl with your own REST API endpoint -->
<Item Key="ServiceUrl">https://xxx.mydomain.com/users/b2c</Item>;
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">ApiKeyHeader</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="Authorization" StorageReferenceId="B2C_1A_RestApiKey" />
</CryptographicKeys>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="givenName" />
<InputClaim ClaimTypeReferenceId="surname" />
<InputClaim ClaimTypeReferenceId="aud" />
<InputClaim ClaimTypeReferenceId="scope" />
<InputClaim ClaimTypeReferenceId="scp" />
<InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="isEnabled" />
<OutputClaim ClaimTypeReferenceId="userId" />
<OutputClaim ClaimTypeReferenceId="accountCode" />
<OutputClaim ClaimTypeReferenceId="role" />
<OutputClaim ClaimTypeReferenceId="env" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
You can get scope with claims resolvers.
Ensure you set the settings.
A more generic way is this.

Azure B2C federated sign out is not complete (identity token is not passed to third party end session endpoint)

I have application which uses Azure B2C as IDP. Azure B2C provides a possible to use local account or federation via OpenIdConnect to third party IDP (Identity Server). I'm using custom policies in B2C. Login works fine but I have issues with sign out. Sign out from federated identity provider is executed but identity token of third party IDP is not passed to the end session endpoint and sign out is not properly executed.
Sign out requests:
GET https://xxxxx.b2clogin.com/xxxxx.onmicrosoft.com/b2c_1a_signup_signin/oauth2/v2.0/logout?post_logout_redirect_uri=https%3A%2F%2Flocalhost%3A44317%2Fsignout-callback-oidc&id_token_hint=xxxxx
GET https://thirdpartyidp.com/idp/connect/endsession <- id_token_hint querystring parameter is missing from here
GET https://thirdpartyidp.com/idp/logout?id=xxxxx
GET https://localhost:44317/signout-callback-oidc?state=xxxxx
I have tested this also with out of box user flow but same problem occurs.
I'm using this technical profile configuration:
<ClaimsProvider>
<Domain>thirdpartyidp</Domain>
<DisplayName>thirdpartyidp</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="thirdpartyidp-OAUTH">
<DisplayName>thirdpartyidp</DisplayName>
<Protocol Name="OpenIdConnect" />
<Metadata>
<Item Key="ProviderName">thirdpartyidp</Item>
<Item Key="METADATA">https://thirdpartyidp.com/idp/.well-known/openid-configuration</Item>
<Item Key="ValidTokenIssuerPrefixes">https://thirdpartyidp.com</Item>
<Item Key="IdTokenAudience">app</Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<Item Key="response_types">code</Item>
<Item Key="response_mode">form_post</Item>
<Item Key="scope">openid profile</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="client_id">app</Item>
<Item Key="SingleLogoutEnabled">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_thirdpartyidp" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
<OutputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="iss" />
<OutputClaim ClaimTypeReferenceId="identityProviderAccessToken" PartnerClaimType="{oauth2:access_token}" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin"/>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
I found two-three year old articles that Azure AD B2C does not support signing you out from the external identity provider. According this pretty new article (https://learn.microsoft.com/en-us/azure/active-directory-b2c/session-behavior?pivots=b2c-custom-policy#sign-out) it should be possible if I understood correctly. Azure B2C definitely attempts federated sign out but it's not complete.
Do I have some kind of custom policy configuration problem or what could be the issue?
You need to configure your relying party to send the Id token during signout.
<UserJourneyBehaviors>
<SingleSignOn Scope="Tenant" EnforceIdTokenHintOnLogout="true"/>
</UserJourneyBehaviors>
I got answer from MS support that passing identity token to third party IDP end session endpoint is not currently supported.

Multi tenant Azure B2C Login - how to get external user email address

I am struggling to figure out how to configure Azure B2C for multi-tenant authentication, in particular getting access to the email address of a user that is logging in via an external Azure AD (we're interested in allowing our customers to log in either via a "Local Account" (email address, managed by B2C) or their own Azure AD).
A key part of the issue I am trying to result is the passing of the logged in users email address through to a REST endpoint where our application needs to do some things internally to inject additional application specific claims, which are used later on. Apart from our REST endpoint receiving the email address, everything else is working.
I've got a "Common AAD" technical profile setup like this:
<TechnicalProfile Id="Common-AAD">
<DisplayName>Work Account</DisplayName>
<Description>Login with your Work Account</Description>
<Protocol Name="OpenIdConnect"/>
<Metadata>
<Item Key="METADATA">https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration</Item>
<Item Key="client_id">my_client_id</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">openid email profile</Item>
<Item Key="response_mode">form_post</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_AADAppSecret"/>
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="oid"/>
<OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid"/>
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="iss" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<OutputClaim ClaimTypeReferenceId="signInName" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<OutputClaim ClaimTypeReferenceId="upn" PartnerClaimType="upn" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId"/>
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin"/>
</TechnicalProfile>
In the orchestration, I am instructing B2C to pass in a bunch of these claims to an application-hosted REST API so that we can do our internal processing:
<TechnicalProfile Id="REST-GetProfile-Dev">
<DisplayName>Do some custom logic</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://the-endpoint.com</Item>
<Item Key="AuthenticationType">None</Item>
<!-- REMOVE the following line in production environments -->
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="objectId" />
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="sub" />
<InputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
<InputClaim ClaimTypeReferenceId="userPrincipalName" />
<InputClaim ClaimTypeReferenceId="displayName" />
<InputClaim ClaimTypeReferenceId="otherMails" />
<InputClaim ClaimTypeReferenceId="upnUserName" />
<InputClaim ClaimTypeReferenceId="alternativeSecurityId" />
<InputClaim ClaimTypeReferenceId="upn" />
<InputClaim ClaimTypeReferenceId="signInName" />
<InputClaim ClaimTypeReferenceId="socialIdpUserId" />
<InputClaim ClaimTypeReferenceId="identityProvider" />
<InputClaim ClaimTypeReferenceId="authenticationSource" />
</InputClaims>
<OutputClaims>
<!-- bunch of app specific claims -->
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
However, I can never seem to get an email address, or anything that contains the email address of the logged in user passing through.
I've tried to track through the processing that's defined in the Custom Policy XML files, and it's challenging. To be honest, I've been researching this and have tried adding all kinds of additional claims to outputs from various steps, but it's just not working for me.
Any help in detailing how to get the email address of a user logged in via an external Azure AD passed into a REST orchestration step would be much appreciated.
Thanks.
** Big Edit **
In response to Jas Suri, I have reset everything, applied the changes below as suggested, but am still not seeing this work.
Here's my TrustFrameworkBase.xml:
TrustFrameworkBase.xml
Here's my TrustFrameworkExtensions.xml:
TrustFrameworkExtensions.xml
Here's my Relying Party (SignInSignUpMulti.xml) file:
SignInSignUpMulti.xml
Now, looking at my scenarios:
When I sign in using a "local" account, I see this type of information pass through to my rest endpoint during the user journey:
{
"objectId": "1e91bfba-17a1-43b6-a451-9896fc3c1061",
"signInNames.emailAddress": "email#example.com",
"displayName": "User DispName",
"signInName": "email#example.com",
"authenticationSource": "localAccountAuthentication"
}
That's perfect. I can take this information and gather additional claims to return and all works exactly as I want.
When I sign in as an AD Account that's attached to my org, I get this:
{
"objectId": "a_guid",
"sub": "Not supported currently. Use oid claim.",
"userPrincipalName": "cpim_a_guid#TENANT.onmicrosoft.com",
"displayName": "ThisIs Correct",
"upnUserName": "14218711-5dd1-4a81-8e04-77bd08298aaf",
"alternativeSecurityId": "{\"type\":6,\"identityProvider\":\"https://login.microsoftonline.com/a_guid/v2.0\",\"key\":\"a_key\"}",
"identityProvider": "https://login.microsoftonline.com/a_guid/v2.0",
"authenticationSource": "socialIdpAuthentication"
}
I am missing an email (or the users Sign In) address.
And, the same happens when I try to sign in as an external AD:
{
"objectId": "a_guid",
"sub": "Not supported currently. Use oid claim.",
"userPrincipalName": "cpim_a_guid#TENANT.onmicrosoft.com",
"displayName": "ThisIs Correct",
"upnUserName": "9c865de4-2898-4b18-998b-7fa151f6623d",
"alternativeSecurityId": "{\"type\":6,\"identityProvider\":\"https://login.microsoftonline.com/a_guid/v2.0\",\"key\":\"a_key\"}",
"identityProvider": "https://login.microsoftonline.com/a_guid/v2.0",
"authenticationSource": "socialIdpAuthentication"
}
If I can work out how to pass through the email address or signin address, then I would be extremely happy.
Event during debugging, if I cause the user to be signed in anyway, I inspect the User.Identity, and while I see claims that my rest api is returning during the journey, I still don't have any claim that resembles the email address I am expecting (hoping) to see.
I can definitely work either way - an email address passed to the REST API, or the email address appearing in the final claim set that the application receives.
Any assistance would be much appreciated.
From Azure AD, all users will come back with a unique_name claim, which is the UPN in their Azure AD. You could also rely on this. If you rely on the email claim from AAD, it will only be present if the user has an Exchange Online inbox. You also have to set it up as an optional Azure AD claim in the AAD Multi Tenant App registration.
Usually the UPN and Email are the same in an Azure AD. So in the AAD technical profile, you could add this output claim to capture the AAD UPN:
<OutputClaim ClaimTypeReferenceId="aadUPN" PartnerClaimType="unique_name"/>
Then in the relying party secion, add this output claim:
<OutputClaim ClaimTypeReferenceId="aadUPN" PartnerClaimType="UPNfromAAD"/>

How to add Slack as an Identity Provider in AAD B2C?

I'd like to add Slack as an Identity Provider to my app using AAD B2C. Is there any example of how to build the Technical Profile for that?
I was able to create a Technical profile to connect to Slack, but I'm having a problem with sending a user_scope parameter instead of the scope parameter. The OAuth2 technical profile only supports "scope" parameter and I'm not able to find a way of sending "user_scope" instead.
I was also able to connect using endpoints that didn't include "v2" in them, but I'm not sure that's the right approach
This is the technical profile I'm using in the ClaimsProvider now. I have anothe ClaimsProvider for AAD multitenant. Didn't modify the relying party at all for Slack.
<TechnicalProfile Id="Slack-OAUTH">
<DisplayName>Slack</DisplayName>
<Protocol Name="OAuth2" />
<Metadata>
<Item Key="ProviderName">slack</Item>
<Item Key="authorization_endpoint">https://slack.com/oauth/v2/authorize</Item>
<Item Key="AccessTokenEndpoint">https://slack.com/api/oauth.v2.access</Item>
<Item Key="ClaimsEndpoint">https://slack.com/api/users.identity</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="UsePolicyInRedirectUri">0</Item>
<Item Key="client_id">ClientID</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="REFERENCE_TO_SECRET_IN_B2C_KEYS" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="user_scope" DefaultValue="identity.basic" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="slack" />
<OutputClaim ClaimTypeReferenceId="user" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="GetIdClaimFromJson" />
<OutputClaimsTransformation ReferenceId="GetNameClaimFromJson" />
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
</TechnicalProfile>
The call to slack works and I'm getting a code back and being redirected to aadb2c, but then I get an exception back. Put the policy in development mode to drop logs into App Insights and got an exception saying: An invalid OAuth response was received: '{0}'.
'Message':'The given key was not present in the dictionary.','Data':{}​
To enable sign-in for users from a Slack account, you need to create a Slack application project.
Sign in to the Slack API with your account credentials.
Select Create New App.
Enter an App Name and select a Development Slack Workspace.
Select Create App.
Under App Credentials, copy the values of Client ID and Client secret. You will need both of them to configure Slack as an identity provider in your tenant. Client secret is an important security credential.
Under Features, select OAuth and Permissions.
Add a new Redirect URL, enter https:/your-tenant-name.b2clogin.com/your-tenant-name.onmicrosoft.com/oauth2/authresp.
Replace your-tenant-name with the name of your tenant. You need to use all lowercase letters when entering your tenant name even if the tenant is defined with uppercase letters in Azure AD B2C.
Click Save URLs.
Create a policy key
You need to store the client secret that you previously recorded in your Azure AD B2C tenant.
Sign in to the Azure portal.
Make sure you're using the directory that contains your Azure AD B2C tenant by clicking the Directory and subscription filter in the top menu and choosing the directory that contains your tenant.
Choose All services in the top-left corner of the Azure portal, and then search for and select Azure AD B2C.
On the Overview page, select Identity Experience Framework - PREVIEW.
Select Policy Keys and then select Add.
For Options, choose Manual.
Enter a Name for the policy key. For example, SlackSecret. The prefix B2C_1A_ is added automatically to the name of your key.
In Secret, enter your client secret that you previously recorded.
For Key usage, select Signature.
Click Create.
Slack claims provider as follows:
<TechnicalProfile Id="Slack-OAUTH">
<DisplayName>Log in with your Slack account</DisplayName>
<Protocol Name="OAuth2"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="AccessTokenEndpoint">https://slack.com/api/oauth.access</Item>
<Item Key="authorization_endpoint">https://slack.com/oauth/authorize</Item>
<Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
<Item Key="ClaimsEndpoint">https://slack.com/api/users.identity</Item>
<Item Key="client_id">Your Slack App Registration Client ID</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">identity.basic</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_slackfederation"/>
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="slackAuthentication" />
<OutputClaim ClaimTypeReferenceId="user" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="slack" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="GetIdClaimFromJson" />
<OutputClaimsTransformation ReferenceId="GetNameClaimFromJson" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
And supporting claims transforms:
<ClaimsTransformation Id="GetIdClaimFromJson" TransformationMethod="GetClaimFromJson">
<InputClaims>
<InputClaim ClaimTypeReferenceId="slackOAuthResponse" TransformationClaimType="inputJson" />
</InputClaims>
<InputParameters>
<InputParameter Id="claimToExtract" DataType="string" Value="id" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" TransformationClaimType="extractedClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="GetNameClaimFromJson" TransformationMethod="GetClaimFromJson">
<InputClaims>
<InputClaim ClaimTypeReferenceId="slackOAuthResponse" TransformationClaimType="inputJson" />
</InputClaims>
<InputParameters>
<InputParameter Id="claimToExtract" DataType="string" Value="name" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="extractedClaim" />
</OutputClaims>
</ClaimsTransformation>
I have been struggling with this same situation where user_scope isn't a valid parameter in my .net core web app.
I tried setting the auth endpoint to:
https://slack.com/oauth/v2/authorize?user_scope=identity.basic+identity.email+identity.team
and that did get past one hurdle, but after I sign in and am redirected back to my web app, it fails to process the claims. I'll update this partial answer if I can get it working, but hopefully, it will help someone figure this out.

Can we set custom headers on RESTful API calls in Azure Active Directory B2C custom policies?

I have successfully created an AAD B2C custom policy which makes a call to my application.
Similar to what can be found here:
Integrate REST API claims exchanges in your Azure AD B2C user journey as validation on user input
and here:
Secure your RESTful services using client certificates
<ClaimsProvider>
<DisplayName>XYZ API</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="XYZ">
<DisplayName>XYZ</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://example.com/api/1.0/Users</Item>
<Item Key="AuthenticationType">ClientCertificate</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<CryptographicKeys>
<Key Id="ClientCertificate" StorageReferenceId="B2C_1A_XYZRestClientCertificate" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="givenName" />
<InputClaim ClaimTypeReferenceId="surname" PartnerClaimType="surname" />
<InputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="displayName" />
<InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="objectId" />
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="otherMails" PartnerClaimType="otherMails" />
</InputClaims>
<OutputClaims>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
Our app likes to use custom HTTP headers to track some information about the caller, such as a transaction id. Is it possible to add HTTP headers similar to claims? Something maybe like:
<InputHeaders>
<InputHeader ClaimTypeReferenceId="objectId" HeaderName="transactionId" />
<InputHeader Value="AzureB2C" HeaderName="callerName" />
</InputHeaders>
Right now, it is not possible to split some claims between various places (e.g. body, headers, query string). I suggest you add a request for this feature at the Azure feedback portal for Azure Active Directory.

Resources