EduardoCMB
EduardoCMB

Reputation: 494

How to query SharePoint Term Store using App only credential in C#

I am trying to build an application that gets terms from a term store in SharePoint Online, using App only permissions. For that, I was hoping to leverage the PnP Framework SDK.

I know for a fact that, currently, the Graph API does not support term store commands using app only permissions (for either v1 or beta).

enter image description here

I can see here how to obtain a ClientContext using app only permissions (client_id and client_secret). But this does not give me access to the term store.

Here, a PnPContext is used to interact with the term store, but the configuration options don't seem to have an option to provide the tenant_id, client_id, and client_secret.

Is there any way to do this?

PS: I only need read access to the term store.

Upvotes: 0

Views: 892

Answers (1)

EduardoCMB
EduardoCMB

Reputation: 494

After further research, I was able to find two solution for this, documented below.

  1. Using PnP Framework
var vars = Environment.GetEnvironmentVariables();
var tenant_id = vars["SHAREPOINT_TENANT_ID"]?.ToString() ?? "";
var sp_client_id = vars["SHAREPOINT_CLIENT_ID"]?.ToString() ?? "";
var sp_client_secret = vars["SHAREPOINT_CLIENT_SECRET"]?.ToString() ?? "";

using (ClientContext cc = new AuthenticationManager().GetACSAppOnlyContext(_siteUrl, sp_client_id, sp_client_secret))
{
    var taxonomySession = TaxonomySession.GetTaxonomySession(cc);
    TermStore termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
    var termGroup = termStore.GetGroup(new Guid(_amlinkTermSetGroupId));

    cc.Load(termGroup,
        group => group.Name,
        group => group.TermSets
            .Include(
                termSet => termSet.Name,
                termSet => termSet.Terms.Include(
                    term => term.Name,
                    term => term.Labels.Include(
                        label => label.Value
                        )
                )
        )
    );

    cc.ExecuteQuery();

    if ((taxonomySession == null) || (termStore == null) || (termGroup == null))
    {
            return;
    }

    foreach (TermSet termSet in termGroup.TermSets)
    {
        foreach (Term term in termSet.Terms)
        {
                // do something with termGroup, termSet, term, and term.Lables
        }
    }
}
  1. Using SharePoint REST API
// You should be caching the token if you got with this option

string resource = $"00000003-0000-0ff1-ce00-000000000000/{domain}@{tenant_id}";

var client_id = $"{sp_client_id}@{tenant_id}";
OAuth2AccessTokenRequest oauth2Request = OAuth2MessageFactory.CreateAccessTokenRequestWithClientCredentials(client_id, sp_client_secret, resource);
oauth2Request.Resource = resource;

// Get token
OAuth2S2SClient authClient = new OAuth2S2SClient();

OAuth2AccessTokenResponse oauth2Response;
try
{
    string authUrl = $"https://accounts.accesscontrol.windows.net/{tenant_id}/tokens/OAuth/2";
    oauth2Response = (OAuth2AccessTokenResponse)authClient.Issue(authUrl, oauth2Request);
}
catch (WebException wex)
{
    Stream? stream = wex.Response?.GetResponseStream();
    if (stream != null)
    {
        using StreamReader sr = new(stream);
        string responseText = sr.ReadToEnd();
        throw new WebException(wex.Message + " - " + responseText, wex);
    }

    throw;
}

string accessToken = oauth2Response.AccessToken;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

var url = $"https://{{domain}}/_api/v2.1/termStore/sets/{_termSetId}/terms";
var response = await client.GetAsync(url);

if (response.IsSuccessStatusCode)
{
    var termsResponse = await response.Content.ReadFromJsonAsync<TermsResponse>();
    // do something with the reponse
}

Some useful links:

SharePoint Online Retrieve term store data including Labels using .Net managed object model

Using .NET Standard CSOM and MSAL.NET for App-Only auth in SharePoint Online

CSOM for .NET Standard with SharePoint App-only principal

Using CSOM for .NET Standard instead of CSOM for .NET Framework (implementation of token cache)

Upvotes: 1

Related Questions