s-KaiNet / sp-request

Simplified SharePoint HTTP client
52 stars 9 forks source link

Issue in retrieving taxonomies #19

Open dma82 opened 2 years ago

dma82 commented 2 years ago

Hi there,

I tried to use this module to retrieve a specific term store but I got an OAuth issue when I tried to hit the following endpoint (which works fine from the browser):

https://.sharepoint.com/_api/v2.1/termStore/groups//sets//terms

So I successfully used _pnpauth and @pnp/sp-taxonomy modules, but I was wondering if I can achieve the same result with sp-request library as it's quite handy the way for the authentication with credentials, and doesn't require other libraries), especially because I had to use an older version of the above modules, which are giving me several warnings (e.g. Accessing non-existent property 'ControlMode' of module exports inside circular dependency ).

If this functionality is already there, would you be able to provide me with an example of how to properly access a term store please? If not, would it be possible to introduce it in the next release?

Thank you very much.

Regards

s-KaiNet commented 2 years ago

Hi,

could you tell me what exact issue do you have? What is the error code or maybe a stack trace?

dma82 commented 2 years ago

Hi @s-KaiNet ,

Unfortunately the only response I'm getting says "OAuth only flow is enabled and the call has not been issued from an app".

I thought there was an issue with the App permissions set for the Term Store but then I was able to successfully get a response from Postman: that's why I switched to @pnp/sp-taxonomy and pnp-auth libraries, which are working fine but the former library is throwing a lot of these warnings:

_(node:2804) Warning: Accessing non-existent property 'ControlMode' of module exports inside circular dependency (Use 'node --trace-warnings ...' to show where the warning was created) (node:2804) Warning: Accessing non-existent property 'FieldTypes' of module exports inside circular dependency etc...

That's why I was hoping to achieve the same result with sp-request and move away from the other libraries.

Anyway, this an extract of my code using the @pnp/sp-taxonomy and pnp-auth (which is working): `

    const bootstrap = require("pnp-auth").bootstrap,

    taxonomy = require("@pnp/sp-taxonomy").taxonomy;

    async function getList () {
              let url = settings.sharepoint.url;

              bootstrap(taxonomy, {
                      username: settings.sharepoint.auth.username, 
                      password: settings.sharepoint.auth.password }, 
                      url);

             const set = _.map(await taxonomy.termStores.getByName("<TAXONOMY_NAME>").getTermSetById("<TERMSET_ID>").terms.get(), 
                list => _.pick(list, ['Id', 'Name', 'PathOfTerm']));

             console.log(set); 
      }

`

Thanks again for your help.

s-KaiNet commented 2 years ago

If pnp-auth works, then sp-request also should work. You could try inspecting HTTP requests to see the difference in the headers and authentication. Also, which kind of authentication do you use for sp-request? Is it the same as for pnp-auth?

dma82 commented 2 years ago

Yes, the authentication works fine, because I was able to upload files in SP as well as update several fields; the problem seems when I try accessing taxonomies:

I tried this with sp-request which gave me the "OAuth" issue:

let url = "https://<TENANT_ID>.sharepoint.com/_api/v2.1/termStore/groups/<GROUP_ID>/sets/<SET_ID>/terms"
const _sprequest = (req.sprequest = sprequest.create(settings.sharepoint.auth));

_sprequest.requestDigest(settings.sharepoint.url) 
        .then((digest) => {
            return _sprequest.get(url, {
                headers: {
                    "Accept": "application/json;odata=verbose",
                    "Content-Type": "application/json;odata=verbose",
                    "X-RequestDigest": digest,
                }
            })
        }).then((response) => {
              //  some code here
        }).catch((err) => {
            //  some code here
        });

Here the URL is different: in my previous example, the URL was simply _https://.sharepoint.com_ , instead this time I tried to directly access the term store (I wasn't sure what else I could do, since it seems SharePoint doesn't have specific methods like 'GetByTitle' for lists when it comes to Taxonomies...)

The documentation I found suggested to use the Client ID and Secret ID, or the Bearer token, but I need to keep using username and password...

Thank you @s-KaiNet :)

s-KaiNet commented 2 years ago

Does it work when you use a Client ID and Secret ID? Also maybe it doesn't work because legacy auth is disabled for you? You can try executing Get-SPOTenant and inspect LegacyAuthProtocolsEnabled property.

dma82 commented 2 years ago

I haven't tried the Client ID and Secret ID, but I've just generated the Bearer token from Postman and I passed it in this way and it worked:

let url = "https://<TENANT_ID>.sharepoint.com/_api/v2.1/termStore/groups/<GROUP_ID>/sets/<SET_ID>/terms"
const _sprequest = (req.sprequest = sprequest.create(settings.sharepoint.auth));

_sprequest({
            url,
            method: "GET",
            headers: {
                Accept: "application/json;odata=verbose",
                "Content-Type": "application/json;odata=verbose",
                "Authorization": "Bearer  <TOKEN GENERATED BY POSTMAN>"
            },
        }).then((response) => {
            res.locals.result = response.body;
            debug(res.locals.result)
            return next();
        }).catch((err) => {
            // Some code here
        });

Is there a different authentication protocol that it's working for the Bearer authorization? OAuth 2 maybe? Or am I missing something else?

s-KaiNet commented 2 years ago

When you use bearer tokens, then it's OAuth, with username\password it's cookie based auth, and it looks like it doesn't work with new taxonomy REST endpoint (_api/v2.1/termStore). Actually, it's just a 1:1 mapping between corresponding MS Graph API, MS Graph, in turn, doesn't support cookie auth and that explains why it doesn't work for you with username and password.

dma82 commented 2 years ago

So I guess there's no workaround for this, is there? :(

s-KaiNet commented 2 years ago

No, except using OAuth type of authentication. Alternatively, if you need a username and passwords and cannot get rid of it, you can implement ROPC flow with a regular Azure AD auth using msal. Once you have a bearer token, you can use a regular fetch API to send requests.

dma82 commented 2 years ago

I'll try that so and see what I get... I guess if I get something working properly I might add send a merge request to extend sp-request :) Thank you again for all your help with this @s-KaiNet, much appreciated!