Microsoft GraphAPI 403 error getting users' events in SPfx app - sharepoint

I wrote a SharePoint SPfx Application hosted on SharePoint Online using the Microsoft GraphAPI to grab user profile information as well as calendar events. Per microsoft documents I declared my scopes inside the package-solution.json file and approved the request via the SharePoint APi management page. I am able to read everybody profile information, however, I get an error 403 when I try to access calendar events but my own. The users' calendar are not private, they open to the entire organization.
Package-solution.json Permission request
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "User.Read"
},
{
"resource": "Microsoft Graph",
"scope": "User.ReadBasic.All"
},
{
"resource": "Microsoft Graph",
"scope": "People.Read"
},
{
"resource": "Microsoft Graph",
"scope": "Calendars.Read"
}
]
}
Admin Approved request image
Screen of approved app permissions
request code:
private _searchUserCalendar(keyword: string): Promise<any[]> {
console.log("connection to GraphAPI event domain")
return new Promise<any[]>((resolve, reject) => {
this._context.msGraphClientFactory.getClient()
.then((client: MSGraphClient): void => {
client
.api(`/users/${keyword}/calendar/events`) // The api i.e> /me | /users
.version('v1.0')
.select("showAs,start,subject, end")
.top(5)
.get((error, response: any, rawResponse?: any) => {
if (error) {
console.log("ooops somethign went wrong get events",error);
reject(error);
}
var users:Array<any>=new Array<any>();
// Map the JSON response to the output array
if (response != null && response != undefined) {
console.log(response);
response.value.map((item: any) => {
console.log("found events for:", item)
}); // mapping over users
}
resolve(users);
});
});
});
}
Error response
{error: {code: "ErrorAccessDenied", message: "Access is denied. Check credentials and try again.",…}}
error: {code: "ErrorAccessDenied", message: "Access is denied. Check credentials and try again.",…}
code: "ErrorAccessDenied"
message: "Access is denied. Check credentials and try again."
innerError: {request-id: "5dca3d4f-ab4c-4237-8ff4-78d8cacbd43b", date: "2020-01-16T19:05:26"}
request-id: "5dca3d4f-ab4c-4237-8ff4-78d8cacbd43b"
date: "2020-01-16T19:05:26"
I've tried everything, any help would be greatly appreciated.
I tested my request on graph explorer and that worked fine
I uninstalled/re-installed the app
I rejected and re-approved the permissions request on the API management dashboard
I changed the request URL from using user id to using emails (only worked for my profile but still didn't work for anybody else)
I had users share their calendar with me and give read/write permissions, still didn't work because the permission is application specific and not user delegated.

User.Read, and User.ReadBasic.All don't have the permissions to do what you are trying to do.
This URL talks about calendar reading shared events.
As an example, Garth has shared with John his default calendar and given John read access. If John has signed into your app and provided delegated permissions (Calendars.Read.Shared or Calendars.ReadWrite.Shared), your app will be able to access Garth's default calendar and events in that calendar as described below.
Can you try adding Calendar.Read.Shared

After trying different permission scopes including the ones suggested by #chad, it seems that Calendar.Read.Shared worked. However, it worked because it is a delegated permission forwhich the users must implicitly share their calendar with the entire organization or the signed-in user. This is misleading and contrary to what I read in the graphAPI documentations found
here under Calendar > Application permission:
Calendars.Read | Read calendars in all mailboxes Allows the app to read
events of all calendars without a signed-in user.
... and
Calendars.Read.Shared | Read user and shared calendars Allows the app
to read events in all calendars that the user can access, including
delegate and shared calendars.
Therefore, according to the previous statements, All i need is Calendars.Read in order to read all events in a user's calendar created by said user. The logic of using Calendars.Read.Shared would be to also read all events shared by the user, including those not created but shared with the user.
Finally, I marked this as answered because it is the only thing that worked for me (somewhat) and not because it solved the original issue. The documentation on this topic is contradictory and confusing. For now this is my answer unless Microsoft changed something or clarify the issue or you found something else or/and my logic is flawed. If my logic and understanding is flawed please post a response and let me know. Afterall, this is what the community is for.
Thank you

Related

Not able to get findMeetingTimes using Microsoft Graph API

I am trying to get and analyze data from office 365 resource room booking data, for that I am using graph API to find meeting times,
https://graph.microsoft.com/v1.0/me/findMeetingTimes ,
this query perfectly working on Microsoft graph explorer after given permissions to calendar.ReadWrite and calendar.ReadWrite.Shared, but this is not working through api call in SharePoint page and postman test with same permissions given in azure WEB API.
it is returning below error
{
"error": {
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again.",
"innerError": {
"request-id": "90f335e7-1955-48c2-a9e9-300ea232e181",
"date": "2018-10-26T07:47:13"
}
}
}
If any suggestion appreciated.
I'm assuming you are using the MSGraphClient inside of SPFx, it is using the delegated permissions (not app permissions as per the comment in this thread). Can you confirm you are using this? https://learn.microsoft.com/en-us/sharepoint/dev/spfx/use-msgraph
This api (https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_findmeetingtimes) requires "Calendars.Read.Shared, Calendars.ReadWrite.Shared" as you stated.
You would need to add additional permissions for this api call to work. As you only get User.Read.All for SPFx with MSGraphClient. This is documented here https://learn.microsoft.com/en-us/sharepoint/dev/spfx/use-aadhttpclient
From your provided request Id, I can see that your request had these scopes, which is missing the Calendars.Read.Shared permissions scope.
"Mail.ReadWrite","User.ReadWrite.All","Calendars.Read","People.Read.All","Group.Read.All","Directory.ReadWrite.All","MailboxSettings.Read","Contacts.ReadWrite","Group.ReadWrite.All","Sites.Manage.All","User.Invite.All","Files.ReadWrite.All","Directory.Read.All","User.Read.All","Files.Read.All","Mail.Read","Calendars.ReadWrite","Mail.Send","MailboxSettings.ReadWrite","Contacts.Read","Sites.FullControl.All","Reports.Read.All"
Look into the permissions of findMeetingTimes. You mode of authentication could be the root cause. For me I was tryint to use Application mode and this is not supported in this API.
I used and alternative api, /calendar/getSchedule to achieve this. If you login as your userid use ME option or use application mode login to login and use {id|userPrincipalName} to get calendar details for any meeting room.
Refer: https://learn.microsoft.com/en-us/graph/api/calendar-getschedule?view=graph-rest-1.0&tabs=http
Graph API Explorer link below provides the basics on how to login and got good examples for Graph to begin with.
https://developer.microsoft.com/en-us/graph/graph-explorer

Unable to get user properties from users imported by Azure AD

I'm using Graph to get all users on my sharepoint online site. The code works just fine expect for one example.
I've the sharepoint users is synced from azure ad, then im not able to get the properties of the user.
Here is the webApiPermissionRequests:
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "User.ReadBasic.All"
},
{
"resource": "Microsoft Graph",
"scope": "Contacts.Read"
},
{
"resource": "Microsoft Graph",
"scope": "User.Read.All"
}
]
The request where i get my users:
const users: MSGraphClient = this.context.serviceScope.consume(MSGraphClient.serviceKey);
users
.api("/users")
.select("displayName,mobilePhone,mail,photo,department,jobTitle,mailNickname")
.top(999)
.get((error, response: any, rawResponse?: any) => {
As i said, Everything works just fine expect when a user is imported from the Azure AD.
Can anyone tell me why all properties except displayName is null when it's an imported user.
UPDATED
I've added a picture. It' is only the Mobile Phone number (Mobiltelefon) that I'm able to get with the api above. The rest of the data and information is not being received. Let's take Office (Kontor) is coming from the azure add and is not is NOT being received in the API.
According to your description, you want to get the user's properties by MS Graph API.
Based on my test, we can get the properties. For your case, we should check the properties whose the value is null.
Check the properties in Azure AD whether it is null.

Azure delegated mail reading across office365 domain (nodejs)

Trying to read/write/update the emails of each user within the domain on office365. I'm using Azure Active Directory and an Azure app. I'm the account admin. I've turned on a whole load of permissions at this stage as not sure which ones are necessary.
I'm programming in Nodejs. So...
Authenticate my app, using OAuth, against Azure so that I can access my own application. <- WORKS.
Request admin rights against the account at this URL: https://login.microsoftonline.com/common/adminconsent?client_id='+clientID+'&redirect_uri'+uri where clientID and uri are replaced. This redirects me to authentication against Microsoft platform. You can see all the permissions I have requested (while debugging) here:
Once I accept the permissions it returns me to my app, where it requests a token from: https://login.windows.net/[my-app-tenant-id]/oauth2/token. That returns the access token. So far so good
After that, I then try and use this token to read a user of my organisations emails (for instance me, but there are a few users I have tried it with). It goes to: https://graph.microsoft.com/v1.0/[userEmailAddress#domain.com/messages. I pass the token as a bearer.
This is the problem, I get
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure.",
"innerError": {
"request-id": "[request-id]",
"date": "2017-03-21T17:31:24"
}
}
}
I have tried this with a couple of URLs, for instance the outlook API, with this url https://outlook.office.com/api/v2.0. I think however that is for simple OAuth and wouldn't work this way anyway.
If anyone can explain how to get the access token to be valid, would be great.
FYI, I am also, simultaneously testing out the npm library azure-graphapi and using:
var clientID = '[client id]'
var clientSecret = '[client secret]'
var tenant = '[tenant id]'
var graph = new GraphAPI(tenant, clientID, clientSecret);
graph.get('users/', function(err, user) {
resp.json({users: user});
})
I can get the list of users. So perhaps I am being stupid and somehow I can use this to read a users email?
Thanks
Maybe you have made a mistake in the request header to get access token.
As you can see, I got a token by sending a POST request to the https://login.microsoftonline.com/common/oauth2/v2.0/token endpoint and passed the value mail.read to the scope parameter in this request.
Now, I am able to get emails of the user with that token.

Access is denied. Check credentials and try again

I am trying to access calendar events using the Microsoft Graph API (https://graph.microsoft.com/v1.0/me/calendarView) on node.js following this permissions guide but I receive the error response :
{
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again.",
"innerError": {
"request-id": "7c2...",
"date": "2016-07-13T21:19:11"
}
}
The call was made with using :
request({url : 'https://graph.microsoft.com/v1.0/me/calendarview', qs : queryParams, 'auth': {'bearer': token}}, function (error, response, body) {
...
});
The request has a valid token and the call to .../me/ via
request({url : 'https://graph.microsoft.com/v1.0/me/', 'auth': {'bearer': token}}, function (error, response, body) {
...
});
returns :
{"#odata.context":"https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id":"<valid_id>",
"businessPhones":[],
"displayName":"<valid_name>",
"givenName":"<valid_name>",
"jobTitle":"<valid_title>",
"mail":"<valid_email>",
"mobilePhone":"<valid_cell>",
"officeLocation":null,
"preferredLanguage":"en-US",
"surname":"<valid_name>",
"userPrincipalName":"<valid_email>"}
So I am assuming this is an issue with permissions set on https://manage.windowsazure.com/ where I created two applications, one for the node server and one for the web client application. I am using passport for authentication and the client id and secret for the web client application.
var AzureOAuthStrategy = require('passport-azure-oauth').Strategy;
passport.use(new AzureOAuthStrategy({
clientId: config.live.clientID,
clientSecret: config.live.clientSecret,
tenantId: config.live.tenant,
resource: 'https://graph.microsoft.com/',
redirectURL: config.live.callbackURL
},
function(accessToken, refreshToken, profile, done) {
Here is what I set for "permissions to other applications" on the node application:
Windows Azure Active Directory :
Delegated Permissions
Read all users' full profiles
Sign in and read user profile
Microsoft graph :
Delegated Permissions
Have full access to user calendars
Read user calendars
(see below)
Delegated Permissions
Access
Here is what I set for "permissions to other application" on the web client application:
Microsoft Graph :
Application Permissions
Read and write calendars in all mailboxes
Read calendars in all mailboxes
Delegated Permissions
Sign users in
Read user contacts
Have full access to user calendars
Read user calendars
Sign in and read user profile
Office Exchange 360 Online :
Application Permissions
Read and write calendars in all mailboxes
Read calendars in all mailboxes
Delegated Permissions
Read user and share calendars
Read and write user and shared calendars
Read all users' basic profiles
Read user profiles
Read user contacts
Read user calendars
Windows Azure Active Directory
Application Permissions : none
Delegated Permissions
Sign in and read user profile
I'm not 100% on what the relationship between the permissions set within the azure management portal and specific end point access. I have read the API scope article but discussion in that article is a bit too conceptual for my needs.
Ultimately I am trying to access and write events to all reservable resources within a tenant id.
I was able to resolve the issue by deleting then regenerating the application through https://manage.windowsazure.com/ then updating the client id and secret. I was, after the fact, able to remove the native client (node) app from the application list and still make the call work.
And while I did not use the reference https://jwt.io/ provided by Fei Xue, I assume it will be invaluable for debugging azure to API permissions in the future.

I'm getting a 403 Forbidden error with the Google Wallet Objects API

I'm getting the following when trying to authenticate using OAuth2 using the Java client library:
Error:
Code was 403
Msg: Forbidden
{
""error"": {
""errors"": [
{
""domain"": ""global"",
""reason"": ""insufficientPermissions"",
""message"": ""Insufficient Permission""
}
],
""code"": 403,
""message"": ""Insufficient Permission""
}
}
What could be causing this "Insufficient Permission" error?
If you are using Google Wallet Objects API, make sure that you share your Account in the Merchant Account with the Service Account Email Address (the one you got when you created your credentials - you can get this one from the cloud console https://cloud.google.com/console, the one that ends with #developer.gserviceaccount.com)
Login to the Merchant Dashboard, click on Account Management and then click on Share. Add the email to the list of users.
You'll also want to share your merchant account with any users you want to give preview access to your classes and discoverables.

Resources