pnp / pnpjs

Fluent JavaScript API for SharePoint and Microsoft Graph REST APIs
https://pnp.github.io/pnpjs/
Other
751 stars 304 forks source link

Issues with PnP JS v4 and Azure AD App in SPFx Webpart - Error: Security Token Failed Audience Restriction Validation #3100

Closed SAgnihotri200895 closed 1 month ago

SAgnihotri200895 commented 1 month ago

What version of PnPjs library you are using

4.x

Minor Version Number

3.0

Target environment

SharePoint Framework

Additional environment details

SPFx : 1.19 PnpJs : v4.3.0

Question/Request

I'm trying to use PnP JS v4 with an Azure AD App in my SPFx webpart, following the retirement of the ACS SharePoint app-only authentication method. Despite following the documentation, I keep encountering the following error:

Error making HttpClient request in queryable [500] ::> ID4183: The Security Token failed Audience restriction validation.

Here’s what I have done so far: Azure AD App Setup:

First Method:

import { SPFx as graphSPFx, graphfi } from "@pnp/graph"; import { SPFx as spSPFx, spfi } from "@pnp/sp"; import { MSAL, MSALOptions } from "@pnp/msaljsclient";

import "@pnp/graph/users"; import "@pnp/sp/webs";

const configuration: MSALOptions = { configuration:{ auth: { authority: "https://login.microsoftonline.com/{tenant Id}/", clientId: "{AAD Application Id/Client Id}" }, },
authParams: { scopes: ["https://graph.microsoft.com/.default"] } };

const graph = graphfi().using(graphSPFx(this.context), MSAL(configuration)); const sp = spfi().using(spSPFx(this.context), MSAL(configuration));

const meData = await graph.me(); const webData = await sp.web();

Second Method:

import type { MSALOptions } from "@pnp/msaljsclient"; import { spfi, SPBrowser } from "@pnp/sp"; import { MSAL, getMSAL } from "@pnp/msaljsclient"; import "@pnp/sp/webs"; import "@pnp/sp/site-users/web";

const options: MSALOptions = { configuration: { auth: { authority: "https://login.microsoftonline.com/{tanent_id}/", clientId: "{client id}", }, cache: { claimsBasedCachingEnabled: true // in order to avoid network call to refresh a token every time claims are requested } }, authParams: { forceRefresh: false, scopes: ["https://{tenant}.sharepoint.com/.default"], } };

const sp = spfi("https://tenant.sharepoint.com/sites/dev").using(SPBrowser(), MSAL(options));

const user = await sp.web.currentUser();

// For logout later on const msalInstance = getMSAL(); const currentAccount = msalInstance.getActiveAccount(); msalInstance.logoutPopup({ account: currentAccount });

Issue: With both methods, I end up getting the same error: Error making HttpClient request in queryable [500] ::> ID4183: The Security Token failed Audience restriction validation.

Additional Information:

Questions:

Thanks in advance!

gretchunkim commented 1 month ago

Just checking to see... Are you able to get the data you need from MS Graph Explorer? Have you received approval permission for the app? - Typically, it's approved by a Tenant Administrator

I do recall getting that message and it went away for me once I have deployed the app and received API approval.

bcameron1231 commented 1 month ago

Hi, I'm curious why you're mixing SPFx behaviors and MSAL together. If you're using SPFx, then you're already logged in and there would be no need to have the Azure AD application, you'd just grant SPFx Application Access to Graph.

SAgnihotri200895 commented 1 month ago

Just checking to see... Are you able to get the data you need from MS Graph Explorer? Have you received approval permission for the app? - Typically, it's approved by a Tenant Administrator

I do recall getting that message and it went away for me once I have deployed the app and received API approval.

Yes, I have approved the permission from Tenant Admin. I haven't explicitly tried graph API for the same as this will lead to couple of more network calls(getting sited id list id etc. ), but will just check that can be alternative for me. if this doesn't work

SAgnihotri200895 commented 1 month ago

Hi, I'm curious why you're mixing SPFx behaviors and MSAL together. If you're using SPFx, then you're already logged in and there would be no need to have the Azure AD application, you'd just grant SPFx Application Access to Graph.

I'm mixing SPFx and MSAL behaviors because we have a requirement, where the SPFx webpart will deployed on one site but the data it will be getting is present on other site collection where not all users will have access. We want the users to access the data only from the webpart and don't want to provide them access.

juliemturner commented 1 month ago

I'm mixing SPFx and MSAL behaviors because we have a requirement, where the SPFx webpart will deployed on one site but the data it will be getting is present on other site collection where not all users will have access.

If the users do not have permissions to the other site collection using MSAL doesn't solve this problem, you're still getting delegated access (which means a token scoped to only what the current user can access). Ergo the better pattern for what you're trying to accomplish would be to build an API (http endpoint) that has "app" permissions to the other site collection and thereby can perform the requests by elevating the permissions for the user making the request specifically for the information you need them to be able to access. I have a really old blog post that touches on this subject, but I think the better resource might be @andrewconnell post Securing an Azure Function App with Entra ID - Works with SharePoint Framework!. If Azure Functions are out of your reach, you could also create a Logic App with an http trigger (the trigger is premium but depending on how much you need to call it may not cost you anything or a minimal amount on a free consumption plan) to do the same thing.

SAgnihotri200895 commented 1 month ago

I'm mixing SPFx and MSAL behaviors because we have a requirement, where the SPFx webpart will deployed on one site but the data it will be getting is present on other site collection where not all users will have access.

If the users do not have permissions to the other site collection using MSAL doesn't solve this problem, you're still getting delegated access (which means a token scoped to only what the current user can access). Ergo the better pattern for what you're trying to accomplish would be to build an API (http endpoint) that has "app" permissions to the other site collection and thereby can perform the requests by elevating the permissions for the user making the request specifically for the information you need them to be able to access. I have a really old blog post that touches on this subject, but I think the better resource might be @andrewconnell post Securing an Azure Function App with Entra ID - Works with SharePoint Framework!. If Azure Functions are out of your reach, you could also create a Logic App with an http trigger (the trigger is premium but depending on how much you need to call it may not cost you anything or a minimal amount on a free consumption plan) to do the same thing.

thanks for quick links, just asking out of curiosity, does pnpjsv4 supports ACS SharePoint App only auth? I do understand Microsoft has already announced its retirement but just wanted to check, if this is still an option for us ?

patrick-rodgers commented 1 month ago

@SAgnihotri200895 - not built in, but we have it in the docs if you want to include it in your project. Not recommended, but it can work, up to you on using it.

juliemturner commented 1 month ago

Not only would I not recommend it, please read between the lines, there's a reason its deprecated and will be completely gone by Nov 2026. So, if you build something with it, it's a ticking timebomb.

bcameron1231 commented 1 month ago

In addition, ACS is App-Only authentication which is not something you can (should) use client side because it requires the use of a client secret. App-Only flows are done server side.

As Julie mentioned, the proper way to do this is to build a middle layer API to handle this for you.

SAgnihotri200895 commented 1 month ago

Thanks @bcameron1231 @juliemturner @patrick-rodgers , will be sticking with middle layer API approach

github-actions[bot] commented 1 month ago

This issue is locked for inactivity or age. If you have a related issue please open a new issue and reference this one. Closed issues are not tracked.