Hello Wael Horchani-TEN,
I understand you’re trying to add a member to a Microsoft Entra security group using Microsoft Graph through Azure API Management (APIM). You can refer below steps that worked in my setup:
Initially, register one application and grant "GroupMember.ReadWrite.All" permission of Application type with admin consent as below:
Make sure to add redirect URI as "https://authorization-manager.consent.azure-apim.net/redirect/apim/YOUR-APIM-SERVICENAME" in Web
platform of application:
Now, create credential provider in your APIM service with Identity provider as Azure Active Directory v1, grant type as client credentials and resource URL as https://graph.microsoft.com like this:
Under Connection
tab, enter client ID and client secret values of your app registration with connection name:
You can confirm it by checking the status of connection, visiting newly created credential provider like this:
Now, create new HTTP API with "https://graph.microsoft.com/v1.0" as Web service URL in your APIM:
In that, create POST operation with URL as /groups/{groupId}/members
:
Make use of below sample policy file code that generates token and use it to call Graph API:
<policies>
<inbound>
<base />
<!-- Extract template parameter -->
<set-variable name="groupId" value="@(context.Request.MatchedParameters["groupId"])" />
<!-- Get token from Credential Manager -->
<get-authorization-context provider-id="graphcred" authorization-id="graphconnection" context-variable-name="auth-context" identity-type="managed" ignore-error="false" />
<!-- Add Authorization and Content-Type headers -->
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + ((Authorization)context.Variables.GetValueOrDefault("auth-context"))?.AccessToken)</value>
</set-header>
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<!-- Rewrite URI to include groupId -->
<rewrite-uri template="@($"/groups/{context.Variables["groupId"]}/members/$ref")" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
In the Test tab, send groupId
template parameter with value and following JSON body manually:
{
"@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/pasteUserId"
}
After sending the request, I got HTTP response as 204 No Content
that confirms the user was successfully added to the group.
Alternatively, you can also make use of below policy code that calls REST API to generate token and use it make Graph call:
<policies>
<inbound>
<base />
<!-- Step 1: Initialize Group Name and User Email -->
<set-variable name="groupName" value="@(context.Request.OriginalUrl.Query.GetValueOrDefault("group_name"))" />
<!-- set-variable name="userEmail" value="@{
var userEmailValue = context.Request.Url.Query.GetValueOrDefault("user_email", "");
return userEmailValue;
}" / -->
<set-variable name="userEmail" value="@(context.Request.OriginalUrl.Query.GetValueOrDefault("user_email"))" />
<!--set-variable name="groupName" value="@(context.Request.MatchedParameters["group_name"])" />
<set-variable name="userEmail" value="@(context.Request.MatchedParameters["user_email"])" /-->
<!-- Step 2: Acquire Microsoft Graph Token -->
<send-request mode="new" response-variable-name="tokenResponse" timeout="20">
<set-url>https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token</set-url>
<set-method>POST</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>@("client_id={client-id}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret={client-secret}&grant_type=client_credentials")</set-body>
</send-request>
<!--Store The Token in "access_token" variable-->
<set-variable name="access_token" value="@(((IResponse)context.Variables["tokenResponse"]).Body.As<JObject>()["access_token"].ToString())" />
<!-- Step 3: Get Group ID by Name -->
<send-request mode="new" response-variable-name="groupResponse" timeout="20">
<set-url>@("https://graph.microsoft.com/v1.0/groups?$filter=displayName eq '" + context.Variables.GetValueOrDefault<string>("groupName") + "'")</set-url>
<set-method>GET</set-method>
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + context.Variables["access_token"])</value>
</set-header>
</send-request>
<!--Store The Group ID in "groupId" variable-->
<set-variable name="groupId" value="@(((IResponse)context.Variables["groupResponse"]).Body.As<JObject>()["value"]?[0]?["id"])" />
<!-- Step 4: Get User ID by Email -->
<send-request mode="new" response-variable-name="userResponse" timeout="20">
<set-url>@("https://graph.microsoft.com/v1.0/users/" + context.Variables.GetValueOrDefault<string>("userEmail"))</set-url>
<set-method>GET</set-method>
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + context.Variables["access_token"])</value>
</set-header>
</send-request>
<!--Store The User ID in "userId" variable-->
<set-variable name="userId" value="@(((IResponse)context.Variables["userResponse"]).Body.As<JObject>()?["id"])" />
<!-- Step 5: Add User to Group-->
<set-method>POST</set-method>
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + context.Variables["access_token"])</value>
</set-header>
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>@("{\"@odata.id\": \"https://graph.microsoft.com/v1.0/directoryObjects/" + context.Variables["userId"] + "\"}")</set-body>
<rewrite-uri template="@("/v1.0/groups/" + context.Variables["groupId"] + "/members/$ref")" copy-unmatched-params="false" />
<set-backend-service base-url="https://graph.microsoft.com" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<choose>
<when condition="@(context.Response.StatusCode == 204)">
<return-response>
<set-status code="200" reason="OK" />
<set-body>{ "message": "User Added Successfully." }</set-body>
</return-response>
</when>
<when condition="@(context.Response.StatusCode == 400)">
<return-response>
<set-status code="200" reason="OK" />
<set-body>{ "message": "Bad Request. User Already Member of The Group Or Invalid User Email." }</set-body>
</return-response>
</when>
<when condition="@(context.Response.StatusCode == 500)">
<return-response>
<set-status code="200" reason="OK" />
<set-body>{ "message": "Bad Request. Invalid Group Name." }</set-body>
</return-response>
</when>
</choose>
</outbound>
<on-error>
<base />
</on-error>
</policies>
Let me know if you still need help with setup or testing. Happy to assist.
Hope this helps!
If this answers your query, do click Accept Answer
and Yes
for was this answer helpful, which may help members with similar questions.
If you have any other questions or are still experiencing issues, feel free to ask in the "comments" section, and I'd be happy to help.