sharepoint online – How to EnsureUser with AD group in REST

I am trying to add AD group to SharePoint site in REST using EnsureUser but I kept getting error message “The specified user c:0+.w|S-1-5-21-1814438218-152777602-930774774-762833 could not be found“. Can someone please tell me what the correct format is for the logonName string? AD is on prem and we are using SP Online. Below is the code:

        string digest = formDigest == "" ? GetRequestDigest() : formDigest;
        string logonNameStr = WebUtility.HtmlEncode("c:0+.w|") + "S-1-5-21-1814438218-152777602-930774774-762833"; <== This seems to be incorrect
        string ensureUserUrl = _siteUrl + "_api/web/EnsureUser"; 
        using (var handler = GetHttpClientHandler(_siteUrl))
            using (HttpClient client = GetHttpClient(handler))
                client.DefaultRequestHeaders.Add("X-RequestDigest", digest);
                var payload = new { logonName = logonNameStr };
                string jsonBody = JsonSerializer.Serialize(payload);
                using (StringContent content = new StringContent(jsonBody))
                    content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose;charset=utf-8");
                    HttpResponseMessage response = client.PostAsync(ensureUserUrl, content).Result;
                    string jsonStr = await response.Content.ReadAsStringAsync();
                    if (!response.IsSuccessStatusCode) //if adding user failed
                        throw new Exception(String.Format("Failed to add AD group {0} to SharePoint site: {1}", groupName, jsonStr));


sharepoint online – Adding security group via EnsureUser failed: ‘The specified user could not be found’

target: SharePoint Online, Azure AD
code environment: Azure Functions, .Net Core

abstract workflow

  1. create a new security group in Azure AD –> take group-id, e.g. “asd-123-asd-123-asd”
  2. create a new O365 group with certain site alias “mySite” and wait for site to be created
  3. retry 30x or until success: add security group as user to the site with EnsureUser function


let my tenant-id be “qwe-345-qwe-345-qwe”

using Microsoft.SharePoint.Client

... SomeClass ... SomeFunction with try/catch and retry logic...
    using (ClientContext clientContext = new ClientContext(""))

        clientContext.ExecutingWebRequest += (s, e) =>
            e.WebRequestExecutor.RequestHeaders("Authorization") = "Bearer " + spoAppToken;

        Web site = clientContext.Web;
        loginName = "c:0t.c|qwe-345-qwe-345-qwe|asd-123-asd-123-asd";
        User spUser = site.EnsureUser(loginName);
        clientContext.Load(spUser, u => u.Id);
        clientContext.ExecuteQueryRetry(4, 500);

        log.LogInformation($"Ensured SharePoint site user!");
        return spUser.Id;


When it fails it throws a Microsoft.SharePoint.Client.ServerException with “Der angegebene Benutzer c:0t.c|qwe-345-qwe-345-qwe|asd-123-asd-123-asd wurde nicht gefunden.” which is german for “The specified user c:0t.c|qwe-345-qwe-345-qwe|asd-123-asd-123-asd could not be found”.


It always fails on the first try with this code. When I add this group via SharePoint UI it works instantly.

The only solution seems to reruning this code multiple times until SharePoint finds the user. I’ve set the rety limit to 30 retries with 10 seconds delay after each retry. In my testing environment this limit was never exceeded but yesterday it exceeded the limit in one of our production environments.

This behavior seems unpredictable and for some time I thought I was using the framework wrong, but since the login name is correct and it is working after some retries the code seems to be right.

I could imagine that there has to happen a certain sync process so that SharePoint knows what groups and users are available in the Active Directory, but why is it working instantly using the UI on the SharePoint site? And should’t “EnsureUser” do exactly that?


Is there a better/more reliable way for ensuring security groups as users on SharePoint sites using CSOM, or another API? Or, am I doing something wrong?

Running 30+ retries doesn’t seem to be the right approach.