Using Groups in Azure AD B2C

Out-of-the-box AAD B2C does not expose any functionality related to Security Groups. They exist as an entity type and can be accessed via the regular Azure AD portal blade but there are no features for including user group membership in a token issued as a result of a user flow. To use groups you will need to add some custom code through custom (IEF) policies. Here is a description of how I accomplished that.

      <ClaimType Id="groups">
        <DisplayName>Comma delimited list of group names</DisplayName>
        <DataType>stringCollection</DataType>
        <UserInputType>Readonly</UserInputType>
      </ClaimType>
        [HttpGet]
        [Route("Groups")]
        public async Task<ActionResult<RESTResponse>> Groups(string objectId)
        {
            await GetAccessTokenAsync();
            var http = new HttpClient();
            http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _GraphToken);
            var queryString = $"users/{userObjectId}/$links/memberOf?api-version=1.6";
            // GET https://graph.windows.net/myorganization/users/{user_id}/$links/memberOf?api-version
            var resp = await http.GetStringAsync($"https://graph.windows.net/{_settings.domain}.onmicrosoft.com/{queryString}");
            var groupArray = (JArray)JObject.Parse(resp)["value"];
            var groups = new List<string>();
            foreach (JObject g in groupArray)
            {
                var groupUrl = g["url"].Value<string>();
                var groupResp = await http.GetStringAsync($"{groupUrl}?api-version=1.6&$select=displayName");
                var name = JObject.Parse(groupResp)["displayName"].Value<string>();
                result.Add(name);
            }
             return new JsonResult(
                new
                {
                    groups
                });
        }
  • Create a Technical Profile in your Base or Extension xml file to call this function from your user journeys:
        <TechnicalProfile Id="GetUserGroups">
          <DisplayName>Retrieves security groups assigned to the user</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://xyz.azurewebsites.net/b2cdata/groups</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">QueryString</Item>
            <Item Key="AllowInsecureAuthInProduction">true</Item>
          </Metadata>
          <InputClaims>
            <InputClaim Required="true" ClaimTypeReferenceId="objectId" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="groups" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>
  • Call the REST function from your signin user journey in a step just before the step where you send claims (or if you want to be fancy add additional steps to determine whether a token even can be issued based on group membership):
        <OrchestrationStep Order="5" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="GetUserGroups" TechnicalProfileReferenceId="GetUserGroups" />
          </ClaimsExchanges>
        </OrchestrationStep>

Your JWT token should now contain the groups claim, e.g.:

{
  "exp": 1556819742,
  "nbf": 1556816142,
  "ver": "1.0",
  "iss": "https://xyz.b2clogin.com/xyz.onmicrosoft.com/v2.0/",
  "sub": "b7a1cb1e-d8d9-41c3-af94-aac0c9c0387c",
  "aud": "e4535fdc-6ae7-4d65-9c5c-bf79b136f932",
  "acr": "b2c_1a_hmhssignin",
  "groups": [
    "Guests",
    "B2CTest1"
  ],
  "tid": "cf6c572c-c72e-4f31-bd0b-75623d040495"
}

Leave a comment