title: Azure B2C - REST API call Error "Message: The claims exchange <Id> specified in step <order> returned HTTP error response that could not be parsed"
body: <p>Thank you and will appreciate some help. I am making a REST api call from a custom policy in Azure B2C. When I call the azure function in a browser, test/run in the auzre portal or via PowerShell Invoke-RestMehod, I get expected results. I get a 200 status OK when i look at the azure function in the portal (via the Monitor blade) or in Application Insights. B2C however keeps complaining with the error &quot;Message: The claims exchange 'GetUserGroups' specified in step '7' returned HTTP error response that could not be parsed.&quot;</p>
  <p>Here is the Claim Type in the TFExtensions.xml</p>
  <pre><code>&lt;ClaimsSchema&gt;
    &lt;ClaimType Id=&quot;groupsMy&quot;&gt;
      &lt;DisplayName&gt;Comma delimited list of group names&lt;/DisplayName&gt;
      &lt;DataType&gt;stringCollection&lt;/DataType&gt;
      &lt;UserInputType&gt;Readonly&lt;/UserInputType&gt;
    &lt;/ClaimType&gt;
  &lt;/ClaimsSchema&gt;
  </code></pre>
  <p>Here is the REST technical profile</p>
  <pre><code>    &lt;TechnicalProfile Id=&quot;GetUserGroups&quot;&gt;
        &lt;DisplayName&gt;Retrieves security groups assigned to the user&lt;/DisplayName&gt;
        &lt;Protocol Name=&quot;Proprietary&quot; Handler=&quot;Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&quot; /&gt;
        &lt;Metadata&gt;
          &lt;Item Key=&quot;ServiceUrl&quot;&gt;https://functionapp.azurewebsites.net/api/GetGroupsFromGraph&lt;/Item&gt;
          &lt;Item Key=&quot;AuthenticationType&quot;&gt;None&lt;/Item&gt;
          &lt;Item Key=&quot;SendClaimsIn&quot;&gt;QueryString&lt;/Item&gt;
          &lt;Item Key=&quot;AllowInsecureAuthInProduction&quot;&gt;true&lt;/Item&gt;
        &lt;/Metadata&gt;
        &lt;InputClaims&gt;
          &lt;InputClaim Required=&quot;true&quot; ClaimTypeReferenceId=&quot;objectId&quot; /&gt;
        &lt;/InputClaims&gt;
        &lt;OutputClaims&gt;
          &lt;OutputClaim ClaimTypeReferenceId=&quot;groupsMy&quot; PartnerClaimType=&quot;groupsMy&quot; /&gt;
        &lt;/OutputClaims&gt;
        &lt;UseTechnicalProfileForSessionManagement ReferenceId=&quot;SM-Noop&quot; /&gt;
      &lt;/TechnicalProfile&gt;
  </code></pre>
  <p>Here is the orchestration step that calls the technical profile</p>
  <pre><code>    &lt;OrchestrationStep Order=&quot;7&quot; Type=&quot;ClaimsExchange&quot;&gt;
        &lt;ClaimsExchanges&gt;
          &lt;ClaimsExchange Id=&quot;GetUserGroups&quot; TechnicalProfileReferenceId=&quot;GetUserGroups&quot; /&gt;
        &lt;/ClaimsExchanges&gt;
      &lt;/OrchestrationStep&gt;
  </code></pre>
  <p>Here is the PowerShell Azure Function</p>
  <pre><code>using namespace System.Net
  
  # Input bindings are passed in via param block.
  param($Request, $TriggerMetadata)
  
  # Write to the Azure Functions log stream.
  Write-Host &quot;PowerShell HTTP trigger function processed a request.&quot;
  
  
  function getAccessTokenMicrosoftGraph($clientid, $tenant, $ClientSecret) {
  
        
      $loginURL = &quot;https://login.microsoftonline.com&quot;
      $resource = &quot;https://graph.microsoft.com&quot; #Microsoft Graph API
  
      # Get an OAuth 2 access token based on client id, secret and tenant
      $body = @{grant_type=&quot;client_credentials&quot;;client_id=$ClientID;client_secret=$ClientSecret;resource=$resource}
      $oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenant/oauth2/token?api-version=1.0 -Body $body
  
      return $oauth
  
  }
  
  
  function returnUserGroups($objectId){
      
      $tenant = &quot;tenant.onmicrosoft.com&quot;
      $ClientID = &quot;xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx&quot;
      $ClientSecret = &quot;%%%%%%%%%%%%%%%%%%%%%%%%%&quot;
      $body = @{grant_type=&quot;client_credentials&quot;;client_id=$ClientID;client_secret=$ClientSecret;resource=$resource}
  
      #get Microsoft Graph Token
      $oauthToken = getAccessTokenMicrosoftGraph -clientid $ClientID -tenant $tenant -ClientSecret $ClientSecret
  
      #Generate the authentication header and make the request
      $AuthHeader =  @{&quot;Authorization&quot;= $oauthToken.access_token;&quot;Content-Type&quot;=&quot;application/json&quot;;&quot;ContentLength&quot;=$body.length }
  
      #Get membership
      $MemberOf = Invoke-WebRequest -Headers $AuthHeader -Uri &quot;https://graph.microsoft.com/beta/users/$objectId/transitiveMemberOf&quot;
      #$MemberOf = Invoke-WebRequest -Headers $AuthHeader -Uri &quot;https://graph.windows.net/$tenant/users/$objectId/$links/memberOf&quot;
  
      #The query will return a JSON object, which you can convert to an array via the following:
      $result = ($MemberOf.Content | ConvertFrom-Json).Value
  
      #parse into comma-separated
      #$groups = ($result | Where-Object {$_.'@odata.type' -eq '#microsoft.graph.group'} | Select-Object DisplayName).DisplayName -join &quot;,&quot;
      $groups = ($result | Where-Object {$_.'@odata.type' -eq '#microsoft.graph.group'} | Select-Object @{name=&quot;groupsMy&quot; ; expression={$_.DisplayName}})
  
  
      return $groups | ConvertTo-Json
      
  
  }
  
  # Interact with query parameters or the body of the request.
  $objectId = $Request.Query.objectId
  if (-not $objectId) {
      $objectId = $Request.Body.objectId
  }
  
  if ($objectId) {
      Write-Host &quot;ObjectID successfully received by fxn&quot;
      $body = $objectId
      $pshell = returnUserGroups -objectId $body  
  }
  else {
      $status = [HttpStatusCode]::BadRequest
      $body = &quot;Please pass a name on the query string or in the request body.&quot;
  }
  
  if ($pshell){
      $status = [HttpStatusCode]::OK
      Write-Host &quot;groups from graph API loaded&quot;
  }
  else {
      $status = [HttpStatusCode]::BadRequest
      $body = &quot;groups not successfully received from Graph API.&quot;
  }  
  
  
  # Associate values to output bindings by calling 'Push-OutputBinding'.
  
  
  Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
      StatusCode = $status
      Body = $pshell | ConvertTo-Json
  })
  </code></pre>
  <p>Finally, my relying party technical profile (SAML)</p>
  <pre><code>&lt;RelyingParty&gt;
      &lt;DefaultUserJourney ReferenceId=&quot;SignUpOrSignIn&quot; /&gt;
        &lt;TechnicalProfile Id=&quot;PolicyProfile&quot;&gt;
          &lt;DisplayName&gt;PolicyProfile&lt;/DisplayName&gt;
          &lt;Protocol Name=&quot;SAML2&quot;/&gt;
          &lt;OutputClaims&gt;
            &lt;OutputClaim ClaimTypeReferenceId=&quot;displayName&quot; /&gt;
            &lt;OutputClaim ClaimTypeReferenceId=&quot;givenName&quot; /&gt;
            &lt;OutputClaim ClaimTypeReferenceId=&quot;surname&quot; /&gt;
            &lt;OutputClaim ClaimTypeReferenceId=&quot;groupsMy&quot; PartnerClaimType=&quot;groupsMy&quot;/&gt;
            &lt;OutputClaim ClaimTypeReferenceId=&quot;email&quot; DefaultValue=&quot;&quot; /&gt;
            &lt;OutputClaim ClaimTypeReferenceId=&quot;identityProvider&quot; DefaultValue=&quot;&quot; /&gt;
            &lt;OutputClaim ClaimTypeReferenceId=&quot;objectId&quot;/&gt;
          &lt;/OutputClaims&gt;
           &lt;SubjectNamingInfo ClaimType=&quot;email&quot; Format=&quot;urn:oasis:names:tc:SAML:2.0:nameid-format:persistent&quot; ExcludeAsClaim=&quot;true&quot;/&gt;
        &lt;/TechnicalProfile&gt;
    &lt;/RelyingParty&gt;
  </code></pre>