azureazure-ad-b2cazure-ad-b2c-custom-policy

Azure B2C Custom Policy - REST Call with Bearer Token from OIDC Step


I have a custom policy/flow for the B2C Identity Experience Framework. I need the user to log into a Microsoft account, get the access token from that, then use that access token to call the /me Graph endpoint to get additional user profile info that isn't available in the OIDC token.

The first step is to do an OIDC login using the OpenIdConnect provider:

<ClaimsProvider>
  <Domain>commonaad</Domain>
  <DisplayName>Common AAD</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="AADCommon-OpenIdConnect">
      <DisplayName>Multi-Tenant AAD</DisplayName>
      <Description>Login with a Microsoft 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">....</Item>
        <Item Key="response_types">code</Item>
        <Item Key="scope">openid profile email User.Read</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_EntraClientSecret"/>
      </CryptographicKeys>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="prompt" PartnerClaimType="prompt" DefaultValue="select_account" AlwaysUseDefaultValue="true" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="oid"/>
        <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
        <!-- A bunch of other claims from the tokens -->
      </OutputClaims>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin"/>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

Now I need to make an HTTP call (to the Graph /me endpoint) and include some of the response values as claims in the output token. This API call uses a Bearer token in the header for authentication.

The B2C documentation shows how to make a RESTful API call and use the output values as claims, and it shows how to do this with a Bearer token in the header using an input claim from a previous step, like so:

<ClaimsProvider>
  <DisplayName>REST APIs</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="REST-GetProfile">
      <DisplayName>Get user profile from Graph API</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://graph.microsoft.com/v1.0/me?$select=jobTitle,officeLocation</Item>
        <Item Key="SendClaimsIn">Header</Item>
        <Item Key="AuthenticationType">Bearer </Item>
        <!-- Use a claim from the previous step as the bearer token -->
        <Item Key="UseClaimAsBearerToken">accessToken</Item>
        <Item Key="AllowInsecureAuthInProduction">false</Item>
      </Metadata>
      <InputClaims>
        <!-- For use in UseClaimAsBearerToken -->
        <InputClaim ClaimTypeReferenceId="accessToken"/>
      </InputClaims>
      <OutputClaims>
        <!-- Claims parsed from your REST API -->
        <OutputClaim ClaimTypeReferenceId="jobTitle" PartnerClaimType="jobTitle"/>
        <OutputClaim ClaimTypeReferenceId="officeLocation" PartnerClaimType="officeLocation"/>
      </OutputClaims>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

So my question is, how do I get the access token from Step 1 (the OpenIdConnect claims provider) as an output claim for use in Step 2? It seems like the OpenIdConnect provider does some internal parsing of the ID token and returns the claims within it, but I can't find any documentation on how I can get (and use) the raw access token.


Solution

  • I found the solution buried in Azure documentation.

    The OAuth2 protocol has an output claim named {oauth2:access_token}, which can be used in the next step for authorization in a REST API. Although it's not documented, this same claim can be output from the OIDC protocol.