samples
samples copied to clipboard
auto-account-linking generating malformed graph API url when using Linkedin
I have deployed auto-account-linkin using setup tool and [this](sample after running the setup tool).
Following this guide I have done all the steps to add linkedin social provider.
When I run the sign in policy and sign in using LinkedIn I get the following error:
Message": "A claim could not be found for lookup claim with id "socialEmail" defined in technical profile with id "AAD-FindLocalAccountWithSocialEmail" policy "B2C_1A_AccountLink_SUSI" of tenant "tenantname.onmicrosoft.com".", "identifierClaimMapping.PolicyClaimType.Id": "socialEmail" "Message": "Claim with id 'socialEmail' was not found in the collection.
So in order to fix it I updated the technical profile as following:
<TechnicalProfiles>
<TechnicalProfile Id="API-LinkedInEmail">
<DisplayName>Get LinkedIn email</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://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">identityProviderAccessToken</Item>
<Item Key="SendClaimsIn">Url</Item>
<Item Key="ResolveJsonPathsInJsonTokens">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="identityProviderAccessToken" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="elements[0].handle~.emailAddress" />
<OutputClaim ClaimTypeReferenceId="socialEmail" PartnerClaimType="email" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
That made the error dissapear but now i am getting this one:
"v": "AAD Request to https://graph.windows.net/b4b9xxxxxxxxxxxxxxxxx659e/users?api-version=1.6&%24filter=signInNames%2fany(x%3ax%2fvalue+eq+%27xxxxxxxxxxxxxx%40gmail.com%27) using method GET as request body is malformed.\r\nResponse: \n{"odata.metadata":"https://graph.windows.net/b4b92xxxxxxxxxxxxxxxxxxxxx-xxxxxx50659e/$metadata#directoryObjects","value":[]}\r\n", "p": false
How the URL is malformed? Is there any control from the custom policy about how this URL is created? Is it possible to achieve linkedin login using auto-account-linking sample?
This is how AAD-FindLocalAccountWithSocialEmail looks like:
<TechnicalProfile Id="AAD-FindLocalAccountWithSocialEmail">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
<Item Key="api-version">1.6</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="socialEmail" PartnerClaimType="signInNames.emailAddress" Required="true" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="localAccountEmail" PartnerClaimType="signInNames.emailAddress" DefaultValue="false" />
<OutputClaim ClaimTypeReferenceId="currentUserIdentities" PartnerClaimType="userIdentities" />
<OutputClaim ClaimTypeReferenceId="extension_haspassword" DefaultValue="false" />
<OutputClaim ClaimTypeReferenceId="localAccountUpn" PartnerClaimType="userPrincipalName" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="ExtractCurrentIssuers" />
<OutputClaimsTransformation ReferenceId="UserIdentitiesContainsCurrentIssuer" />
<OutputClaimsTransformation ReferenceId="AppendNewUserIdentityToCurrentUserIdentities" />
</OutputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
This is how my user journey and sub journey looks like:
<UserJourneys>
<UserJourney Id="AccountLinkSignUpOrSignIn" DefaultCpimIssuerTechnicalProfileReferenceId="JwtIssuer">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="MicrosoftAccountExchange" />
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="LinkedInExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Check if the user has selected to sign in using one of the social providers -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH-SignIn" />
<ClaimsExchange Id="MicrosoftAccountExchange" TechnicalProfileReferenceId="MSA-OIDC-SignIn" />
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail-HasEmailFlagged" />
<ClaimsExchange Id="LinkedInExchange" TechnicalProfileReferenceId="LinkedIn-OAuth2" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Extra step for LinkedIn to get the email -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>identityProvider</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>identityProvider</Value>
<Value>linkedin.com</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="GetEmail" TechnicalProfileReferenceId="API-LinkedInEmail" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- if social account auth, try find an account with the incoming email, and return the LocalAccountEmail-->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>localAccountAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="FindLocalAccountWithSocialEmail" TechnicalProfileReferenceId="AAD-FindLocalAccountWithSocialEmail" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Subjourney :
Handle the case of the incoming social accounts email matching a an email of another account in directory (social/local).
Since all signups will provision as local (as signInName.emailaddress is being populated for local and social sign ups)
If LocalAccountEmail exists, then this Social ID must be linked to an existing Local Account unless its already linked -->
<OrchestrationStep Order="5" Type="InvokeSubJourney">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>localAccountAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>LocalAccountEmail</Value>
<Value>false</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>containsIssuerAlready</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<JourneyList>
<Candidate SubJourneyReferenceId="HandleLinkLocalToSocial" />
</JourneyList>
</OrchestrationStep>
<!-- Subjourney :
Handle new social account sign in.
If LocalAccountEmail does not exist, and is not LocalAccount auth, then this Social Id must be provisioned as normal
If its a local account auth, then skip this entirely -->
<OrchestrationStep Order="6" Type="InvokeSubJourney">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>localAccountAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>LocalAccountEmail</Value>
<Value>false</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>localAccountAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<JourneyList>
<Candidate SubJourneyReferenceId="ProvisionOrSignInNewSocialAccount" />
</JourneyList>
</OrchestrationStep>
<OrchestrationStep Order="7" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="8" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
</UserJourneys>
<SubJourneys>
<SubJourney Id="ProvisionOrSignInNewSocialAccount" Type="Transfer">
<OrchestrationSteps>
<!-- should always be no account present in this path -->
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadUsingUserIdentity" TechnicalProfileReferenceId="AAD-UserReadUsingUserIdentity-NoError" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Show self-asserted page only if the directory does not have the user account already (i.e. we do not have an objectId). -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social-v2" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingUserIdentity" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
</SubJourney>
<SubJourney Id="HandleLinkLocalToSocial" Type="Transfer">
<OrchestrationSteps>
<!-- if we got an local account email now and is social auth not associated with this email,
present page to sign in with local or any other socials as account exists with this email -->
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.idpselections">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>localAccountAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<!-- skip if this social idp already linked to local account -->
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>containsIssuerAlready</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_haspassword</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsProviderSelections DisplayOption="ShowSingleProvider">
<ClaimsProviderSelection TargetClaimsExchangeId="LinkFacebookExchange1" />
<ClaimsProviderSelection TargetClaimsExchangeId="LinkMSAExchange1" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<!-- skip if this social idp already linked to local account -->
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>executedLoginWithLocalToLink</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_haspassword</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="LinkFacebookExchange1" TechnicalProfileReferenceId="Facebook-OAUTH-Link" />
<ClaimsExchange Id="LinkMSAExchange1" TechnicalProfileReferenceId="MSA-OAUTH-Link" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>localAccountAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_haspassword</Value>
<Value>False</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<!-- skip if this social idp already linked to local account -->
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>containsIssuerAlready</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsProviderSelections DisplayOption="ShowSingleProvider">
<ClaimsProviderSelection TargetClaimsExchangeId="LinkFacebookExchange2" />
<ClaimsProviderSelection TargetClaimsExchangeId="LinkMSAExchange2" />
<ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninEmailExchangeLink2" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<!-- skip if this social idp already linked to local account -->
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>executedLoginWithLocalToLink</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_haspassword</Value>
<Value>False</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="LinkFacebookExchange2" TechnicalProfileReferenceId="Facebook-OAUTH-Link" />
<ClaimsExchange Id="LinkMSAExchange2" TechnicalProfileReferenceId="MSA-OAUTH-Link" />
<ClaimsExchange Id="LocalAccountSigninEmailExchangeLink2" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email-Link" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- use the userIdentity from the linking auth to check if the objectId of that user matches the local account from the initial call-->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>executedLoginWithLocalToLink</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="LookupProofAccount" TechnicalProfileReferenceId="AAD-UserReadUsingUserIdentityToLink-NoError" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Now comapre the email from Social Link vs Local-->
<OrchestrationStep Order="6" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>executedLoginWithLocalToLink</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="CheckProofOfSocialObjectIdMatchesLocal" TechnicalProfileReferenceId="CheckProofOfSocialObjectIdMatchesLocal" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Kill journey if proof of social didnt match local email to begin with-->
<OrchestrationStep Order="7" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>executedLoginWithLocalToLink</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>SocialProofMatchesLocalAccount</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="ProofOfSocialEmailDidntMatchLocalEmail" TechnicalProfileReferenceId="SelfAsserted-Error" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Sample: Link the new social account. -->
<OrchestrationStep Order="8" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>containsIssuerAlready</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="UpdateUserIdentities" TechnicalProfileReferenceId="AAD-UpdateUserIdentitiesToLocalUser" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="9" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="10" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
</SubJourney>
</SubJourneys>