Search code examples
azureazure-active-directoryazure-ad-b2cidentity-experience-framework

Azure AD B2C LinkedIn profile picture


I'm currently using Azure AD B2C with LinkedIn integration to log into my application. The login process is working and i get back several claims regarding the user such as name and e-mail address.

I want to get the LinkedIn profile picture in order to have a default profile picture in my app. I try to use custom policies but I can't get them to work. I tried editing the TrustFrameworkBase.xml and TrustFrameworkExtensions.xml but nothing came out of it yet. I added linkedIn as a claimprovider in my TrustFrameworkExtensions.xml

 <ClaimsProvider>
  <Domain>linkedin.com</Domain>
  <DisplayName>LinkedIn</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="LinkedIn-OAUTH">
      <DisplayName>LinkedIn</DisplayName>
      <Protocol Name="OAuth2" />
      <Metadata>
        <Item Key="ProviderName">linkedin</Item>
        <Item Key="authorization_endpoint">https://www.linkedin.com/oauth/v2/authorization</Item>
        <Item Key="AccessTokenEndpoint">https://www.linkedin.com/oauth/v2/accessToken</Item>
        <Item Key="ClaimsEndpoint">https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,headline, picture-url)</Item>
        <Item Key="SendClaimsIn">Body</Item>
        <Item Key="ClaimsEndpointAccessTokenName">oauth2_access_token</Item>
        <Item Key="ClaimsEndpointFormatName">format</Item>
        <Item Key="ClaimsEndpointFormat">json</Item>
        <Item Key="scope">r_emailaddress r_basicprofile</Item>
        <Item Key="HttpBinding">POST</Item>
        <Item Key="UsePolicyInRedirectUri">0</Item>
        <Item Key="client_id"><CLIENT ID OF LINKEDIN APP></Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="client_secret" StorageReferenceId="B2C_1A_LinkedInSecret" />
      </CryptographicKeys>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="id" />
        <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" />
        <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName" />
        <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailAddress" />
        <!--<OutputClaim ClaimTypeReferenceId="jobTitle" PartnerClaimType="headline" />-->
        <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="linkedin.com" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
        <OutputClaim ClaimTypeReferenceId="extension_Picture" PartnerClaimType="pictureUrl" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
        <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
        <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
        <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
      </OutputClaimsTransformations>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

I Also added this Claimtype in my TrustFrameworkBase.xml

  <ClaimType Id="extension_Picture">
    <DisplayName>Picture</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="picture" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="picture" />
      <Protocol Name="SAML2" PartnerClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/extension_Picture" />
    </DefaultPartnerClaimTypes>
    <UserHelpText>Your picture.</UserHelpText>
    <UserInputType>TextBox</UserInputType>
  </ClaimType>

Does someone know how to properly implement the claims on Azure so that i can get a profile picture from linkedIn?


Solution

  • Here is how I have retrieved the picture-url field for the LinkedIn user and then issued a picture claim in the ID token.

    1: Complete the Azure Active Directory B2C: Get started with custom policies steps with one of the social account policies such as the SocialAndLocalAccounts one.

    2: Declare a picture claim in the extensions file:

    <ClaimType Id="picture">
      <DisplayName>Picture</DisplayName>
      <DataType>string</DataType>
      <DefaultPartnerClaimTypes>
        <Protocol Name="OAuth2" PartnerClaimType="picture" />
        <Protocol Name="OpenIdConnect" PartnerClaimType="picture" />
      </DefaultPartnerClaimTypes>
    </ClaimType>
    

    3: Add both the picture-url field to the ClaimsEndpoint metadata item and the picture output claim to the LinkedIn-OAUTH technical profile in the extensions file:

    <ClaimsProvider>
      <Domain>linkedin.com</Domain>
      <DisplayName>LinkedIn</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="LinkedIn-OAUTH">
          <DisplayName>LinkedIn</DisplayName>
          <Protocol Name="OAuth2" />
          <Metadata>
            <Item Key="ProviderName">linkedin</Item>
            <Item Key="authorization_endpoint">https://www.linkedin.com/oauth/v2/authorization</Item>
            <Item Key="AccessTokenEndpoint">https://www.linkedin.com/oauth/v2/accessToken</Item>
            <Item Key="ClaimsEndpoint">https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)</Item>
            <Item Key="ClaimsEndpointAccessTokenName">oauth2_access_token</Item>
            <Item Key="ClaimsEndpointFormatName">format</Item>
            <Item Key="ClaimsEndpointFormat">json</Item>
            <Item Key="scope">r_emailaddress r_basicprofile</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="UsePolicyInRedirectUri">0</Item>
            <Item Key="client_id">Your LinkedIn application client ID</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_LinkedInSecret" />
          </CryptographicKeys>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="id" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="formattedName" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailAddress" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="linkedin.com" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
            <OutputClaim ClaimTypeReferenceId="picture" PartnerClaimType="pictureUrl" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
          </OutputClaimsTransformations>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    

    4: Issue the picture claim in the sign-up or sign-in relying party file:

    <RelyingParty>
      <DefaultUserJourney ReferenceId="SignUpOrSignIn" />
      <TechnicalProfile Id="PolicyProfile">
        <DisplayName>PolicyProfile</DisplayName>
        <Protocol Name="OpenIdConnect" />
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="displayName" />
          <OutputClaim ClaimTypeReferenceId="email" />
          <OutputClaim ClaimTypeReferenceId="picture" />
          <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
          <OutputClaim ClaimTypeReferenceId="identityProvider" />
        </OutputClaims>
        <SubjectNamingInfo ClaimType="sub" />
      </TechnicalProfile>
    </RelyingParty>
    

    The ID token is then issued with a picture claim such as:

    "picture": "https://media.licdn.com/dms/image/C5603AQGuMHK965UNqA/profile-displayphoto-shrink_100_100/0?e=1537401600&v=beta&t=e0yFYCn0QTn-dY7FJH_YOjIUY8cumr1llEnAMUVq38g"