Closed gruering closed 5 months ago
That doesn't really make any sense, unless you're making graph calls you don't need graph permissions...
If you want to share code that provides a full picture from creating the SPFI object through calls that are failing I can see if anything jumps out.
Can you share the scopes and calls you are making?
const token = await provider.getToken(`${personalUrl.protocol}//${personalUrl.hostname}`, true);
// create new context with personal site token
const mySp = spfi(personalUrl.href).using(SPFx(context?.sharePointContext), BearerToken(token));
// check if the list was created, or if it already existed
const sfMyReservations = await mySp.web.lists.ensure(
"sfMyReservations", "Reservation List", 100, false, { Hidden: true }
)
I get a 403 error when trying to create a list without setting the following scopes on the graph: Sites.Manage.All, Sites.ReadWrite.All After adding the scopes to code works. (Please note that this issue only occurs when accessing the mysite from another site which is the reason why I am using the bearer token)
What is provider.getToken
? That doesn't appear to be part of our library.
So I'm guessing somewhat because I don't have access to your package.json but the first line is
const token = await provider.getToken(
${personalUrl.protocol}//${personalUrl.hostname}, true);
Are you by chance using the Microsoft Graph Toolkit? That's the only thing I can think of that uses the term 'provider'...
const provider = await context.aadTokenProviderFactory.getTokenProvider();
Sorry, I did not post all the code. No, I am not using the Graph Tookit. I am just using the aadTokenProvider of the context.
here you have all the lines together...
const personalUrl = new URL(profile.PersonalUrl);
// get a bearer token from the personal site url
const provider = await context.aadTokenProviderFactory.getTokenProvider();
const token = await provider.getToken(`${personalUrl.protocol}//${personalUrl.hostname}`, true);
// create new context with personal site token
const mySp = spfi(personalUrl.href).using(SPFx(context), BearerToken(token));
// check if the list was created, or if it already existed
const sfMyReservations = await mySp.web.lists.ensure(
"sfMyReservations", "Reservation List", 100, false, { Hidden: true }
)
context is from the WebPart
Do you have anything in your package-solution.json file under "webApiPermissionRequests"?
yes, the already mentioned permissions:
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "Sites.ReadWrite.All"
},
{
"resource": "Microsoft Graph",
"scope": "Sites.Manage.All"
}
],
yes, the already mentioned permissions:
Yes but you didn't share them... and the train of things hasn't been super clear, I'm trying to remote debug your solution via asynchronous posts...
So what I think you're saying is if you remove those requests and then rebuild/redeploy the code the ensures the lists fails with a 403?
I have created a demo sample for the issue and uploaded it to my github repository: https://github.com/gruering/MySiteSample/blob/main/src/webparts/mySiteSample/MySiteSampleWebPart.ts
It is a simple WebPart that tries to create a list in the MySite and write an entry if available. The sample does not contain the scopes in webApiPermissionRequests. If you try it on a tenant without these permissions on the "SharePoint Online Client Extensibility Web Application Principal" it will result in 403 errors.
If you add Sites.Manage.All and Sites.ReadWrite.All to the graph (and after a short delay) the solutions works.
So this is an interesting scenario where when you request a token on the Personal Sites, either the Graph scope or a SharePoint scope actually works (this is a bug in my opinion, cc: @patrick-rodgers). I've seen this in practice and have reproduced it myself.
However, because you're not calling Graph APIs, I would remove the Graph API scope if you don't need it. What you would need to add to the SharePoint Online Client Extensibility Principal would be the SharePoint AllSites.Manage permission to do what you're trying to achieve.
Many thanks to all of you for your feedbacks @patrick-rodgers, @juliemturner, @bcameron1231. I was able to test the code successfully with the SharePoint "AllSites.Manage" permission. I will remove the graph permissions and use those. Makes much more sense now :smile: I thought I had already tested these, but I probably didn't wait long enough for the token to get the permissions.
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.
What version of PnPjs library you are using
3.x
Minor Version Number
3.23.0
Target environment
All
Additional environment details
Accessing users personal site from an SPFx WebPart on another site and thus from a different base url (-my)
Question/Request
This is a follow-up question to my original question https://github.com/pnp/pnpjs/issues/2966 that was already answered by @patrick-rodgers and @juliemturner . As already mentioned updating my code to use the current context besides the bearer token to create a new spfi works:
const mySp = spfi(personalUrl.href).using(SPFx(context), BearerToken(token));
What still irritates me, however, is that I need authorizations on the graph for this. Although I am only using the SharePoint endpoint, my code only works when adding the permissions scopes to the graph. If I do not add the scopes, they are also missing on the bearer token and the calls to the SharePoint sites fail with 403.
As it is normally not needed to add graph permissions to access SharePoint endpoints, I wanted to make sure if this is really the right way to do it.
Please let me know if there is a simpler way to access the users personal site without needing additional permissions scopes on the graph.
Thank you for your support.