Fetch events from shared calendar with Office 365 REST API - microsoft-graph-api

Loading shared calendar from a user works so far.
However, as soon as you want to load the events, we get the following error message:
ErrorAccessDenied
Access is denied. Check credentials and try again.
The URL looks like this:
https://outlook.office.com/api/v2.0/users/{userName}/calendars/{sharedCalendarId}/calendarView
Query:
{
"query": {
"$select": "Subject,Location,Start,End,IsAllDay,BodyPreview,Extensions",
"$expand": "Extensions($filter=Id eq \"Microsoft.OutlookServices.OpenTypeExtension.custom.string.here\")",
"startDateTime": "2018-07-09T22:00:00.000Z",
"endDateTime": "2018-11-09T23:00:00.000Z"
},
"headers": {
"Prefer": [
"odata.track-changes",
"odata.maxpagesize=200"
]
}
}
The following scopes were set:
"openid",
"profiles",
"offline_access", // for refresh token
"https://outlook.office.com/calendars.readwrite",
"https://outlook.office.com/calendars.read.shared",
"https://outlook.office.com/calendars.readwrite.shared"

The Outlook REST API requests are always performed on behalf of the current user (authenticated user). That's why the endpoint /me/calendars works but users/{userId}/calendars does not. You can not get access to another user's calendar using this API. More information is provided here.
To access the other user's calendar you should switch to Microsoft Graph API. Then you could use the following endpoints:
Using https://graph.microsoft.com/v1.0/
GET /me/calendar/calendarView
GET /users/{id | userPrincipalName}/calendar/calendarView
GET /groups/{id}/calendar/calendarView
Remember to specify permissions for accessing user's calendars.

Related

Using RSC To Access Chat Messages with Microsoft Graph

I am building a Teams chat-bot that looks at the history of messages in the current chat/channel whilst in conversation with the user.
My bot has been granted all the RSC (Resource-Specific Content) Permissions it needs (see image below)
Here is the relevant parts of the manifest:
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.11/MicrosoftTeams.schema.json",
"version": "1.0.0",
"manifestVersion": "1.11",
"id": "bd33f8b1-b593-433c-926e-44a27c1bd94a",
...
"permissions": [
"identity",
"messageTeamMembers"
],
...
"bots": [
{
"botId": "e6d93739-a8ab-412d-a4f6-b6f514a3451a",
"scopes": [
"team",
"personal",
"groupchat"
],
"isNotificationOnly": false,
"supportsFiles": true
}
],
"validDomains": [],
"webApplicationInfo": {
"id": "e6d93739-a8ab-412d-a4f6-b6f514a3451a",
"resource": "https://RscBasedStoreApp",
"applicationPermissions": [
"TeamSettings.Read.Group",
"ChannelMessage.Read.Group",
"TeamSettings.Edit.Group",
"ChannelSettings.ReadWrite.Group",
"Channel.Create.Group",
"Channel.Delete.Group",
"TeamsApp.Read.Group",
"TeamsTab.Read.Group",
"TeamsTab.Create.Group",
"TeamsTab.ReadWrite.Group",
"TeamsTab.Delete.Group",
"Member.Read.Group",
"Owner.Read.Group",
"ChatSettings.Read.Chat",
"ChatSettings.ReadWrite.Chat",
"ChatMessage.Read.Chat",
"ChatMember.Read.Chat",
"Chat.Manage.Chat",
"TeamsTab.Read.Chat",
"TeamsTab.Create.Chat",
"TeamsTab.Delete.Chat",
"TeamsTab.ReadWrite.Chat",
"TeamsAppInstallation.Read.Chat",
"OnlineMeeting.ReadBasic.Chat",
"Calls.AccessMedia.Chat",
"Calls.JoinGroupCalls.Chat",
"TeamsActivity.Send.Chat"
]
}
}
Note: the bot has permission to read messages in chats and channels. Specifically, my problem affects chats and not channels (which I can get messages from fine).
In order to do this, I get a JWT token for the bot account, accessing the Graph API like so:
GraphServiceClient<?> gsc = GraphServiceClient.builder()
.authenticationProvider(u -> mac.getToken())
.buildClient();
Next, I am using the Graph API to pull back these messages. For messages in channels I can do:
gsc.teams("some group id")
.channels("team id")
.messages()
.buildRequest(Collections.emptyList()).get()));
This works fine.
For chats, I am doing something like:
gsc.chats("29:13qY8hmfkJinH9-v7rYKjCNFHYFJXKbjqR-NyzyKzL694npelHJoq5HrVtqJLRYo79OYeHGQq-bhtJM5N-yKXyQ")
.messages()
.buildRequest().get()));
However, this time I get an error from the Graph API:
[Some information was truncated for brevity, enable debug logging for
more details] com.microsoft.graph.http.GraphServiceException: Error
code: Forbidden Error message: Invoked API requires Protected API
access in application-only context when not using Resource Specific
Consent. Visit
https://learn.microsoft.com/en-us/graph/teams-protected-apis for more
details.
GET
https://graph.microsoft.com/v1.0/chats/29:13qY8hmfkJinH9-v7rYKjCNFHYFJXKbjqR-NyzyKzL694npelHJoq5HrVtqJLRYo79OYeHGQq-bhtJM5N-yKXyQ/messages
SdkVersion : graph-java/v5.6.0
I am at a loss to explain why querying channels works fine but querying chats fails.
Any help gratefully appreciated!
This is a protected API and in order to use it you will first need to make a formal request to Microsoft Graph, asking for permissions to use the API without any user interaction
Here is the list of protected APIs. You need to fill this form to get the required permissions.
To request access to these protected APIs, complete the following
request form. We review access requests every Wednesday and deploy
approvals every Friday, except during major holiday weeks in the U.S.
Submissions during those weeks will be processed the following
non-holiday week.
The other option would be to use delegated flow.

Microsoft Graph translateExchangeIds not returning the same id as EWS

I am working with both EWS and the Graph API.
I would like to create events (online meetings with skype/teams) in an calendar that is already available via EWS.
To match the calendar to the one available via Graph API i try to use https://learn.microsoft.com/en-us/graph/api/user-translateexchangeids
The calendar i created has this id when returned by the FindFolder call:
<t:FolderId Id="AAMkAGNiY2YxMjY3LTUxYjgtNGI1Yy1hOTM2LTU4MTM5OTZiNjdjYgAuAAAAAABW2gY0kRG1SqggDTNZN6i8AQAPJkKZ1XJkQ6huFmcVa6XaAAGixNZ3AAA=" ChangeKey="..."/>
<t:DisplayName>Test</t:DisplayName>
I create a request to the graph api:
{
"inputIds": [
"AAMkAGNiY2YxMjY3LTUxYjgtNGI1Yy1hOTM2LTU4MTM5OTZiNjdjYgAuAAAAAABW2gY0kRG1SqggDTNZN6i8AQAPJkKZ1XJkQ6huFmcVa6XaAAGixNZ3AAA="
],
"sourceIdType": "ewsId",
"targetIdType": "restId"}
and get the result
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.convertIdResult)",
"value": [
{
"sourceId": "AAMkAGNiY2YxMjY3LTUxYjgtNGI1Yy1hOTM2LTU4MTM5OTZiNjdjYgAuAAAAAABW2gY0kRG1SqggDTNZN6i8AQAPJkKZ1XJkQ6huFmcVa6XaAAGixNZ3AAA=",
"targetId": "AAMkAGNiY2YxMjY3LTUxYjgtNGI1Yy1hOTM2LTU4MTM5OTZiNjdjYgAuAAAAAABW2gY0kRG1SqggDTNZN6i8AQAPJkKZ1XJkQ6huFmcVa6XaAAGixNZ3AAA="
}
]
}
However, if i call https://graph.microsoft.com/v1.0/me/calendars i get a different id
"id": "AAMkAGNiY2YxMjY3LTUxYjgtNGI1Yy1hOTM2LTU4MTM5OTZiNjdjYgBGAAAAAABW2gY0kRG1SqggDTNZN6i8BwBIq5JjIBY-RqWQllrF0GSkAAAAB353AAAPJkKZ1XJkQ6huFmcVa6XaAAGixNowAAA=",
"name": "Test",
Is there a way to match the (ews) calendar i already have to the one returned by the Graph API?
This is a shot in the dark, because I've never dug this deeply into the weeds on the Graph Ids, but you might try calling Graph with the header that selects "immutable ids." I tried to find some details on what this actually means without much luck.
The header is:
request.Header("Prefer", "IdType=\"ImmutableId\"");
HTH, and if not, sorry for guessing.

unable to get given_name and family_name from azure v2 token endpoint

In the manifest of my application registration I've configured to retrieve the given_name and family_name claims (through the UI, the resulting manifest looks like this):
"idToken": [
{
"name": "family_name",
"source": "user",
"essential": false,
"additionalProperties": []
},
{
"name": "given_name",
"source": "user",
"essential": false,
"additionalProperties": []
}
],
During the redirect I add the profile scope along with the given_name and family_name scopes, which results in the following error.
Message contains error: 'invalid_client', error_description: 'AADSTS650053: The application 'REDACTED' asked for scope 'given_name' that doesn't exist on the resource '00000003-0000-0000-c000-000000000000'. Contact the app vendor.
Any ideas? As I understand that is what is required to configure these optional claims on the v2.0 endpoint as described here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims#v20-specific-optional-claims-set
You should only use the profile 'scope', which should result in you receiving the given_name and family_name 'claims'. That's standard behaviour for an Authorization Server, which will then either:
Return the name details directly in the id token
Or allow you to send an access token to the user info endpoint to get the name details
However, Azure v2 is very Microsoft specific, and user info lookup can be painful and involve sending a separate type of token to the Graph user info endpoint. Hopefully you won't have to deal with that and you will get the name details directly in the id token.
I had a scenario where my API (which only received an access token) needed to get user info, and I solved it via steps 14 - 18 of this write up, but it's a convoluted solution.
Once you configure optional claims for your application through the UI or application manifest. you need to provide profile Delegated permissions for the application.

Microsoft Graph webhooks - subscribe to user calendars

I have a problem with my Microsoft Graph webhook subscriptions to /me/events. What I want to do is to subscribe to all user calendars.
First I have created the new app in https://apps.dev.microsoft.com using my personal Microsoft account.
Then in my app I subscribe to /me/events notifications using access token:
POST https://graph.microsoft.com/beta/subscriptions
{
"changeType": "created,updated",
"notificationUrl": "https://xxxxx.ngrok.io/notification-url",
"resource": "/me/events",
"expirationDateTime": "2018-11-14T09:40:10.933Z",
"clientState": "xxxx-xxxx-xxxx-xxxx"
}
My notificationUrl receives validation request to which my app responds with 200 OK and validation token. After that the POST request returns me my subscription:
{
"#odata.context" : "https://graph.microsoft.com/beta/$metadata#subscriptions/$entity",
"id" : "2773aa4c-e983-4d15-9236-xxxxxxxx",
"resource" : "/me/events",
"applicationId" : "d551ec34-8d44-4cc6-9b88-xxxxxxxx",
"changeType" : "created,updated",
"clientState" : "xxxx-xxxx-xxxx-xxxx",
"notificationUrl" : "https://xxxxx.ngrok.io/notification-url",
"expirationDateTime" : "2018-11-14T09:40:10.933Z",
"creatorId" : "00000000000"
}
This subscription works fine but only for one, default calendar in Outlook. I don't receive any notifications if I create, update events in any other calendars that exists in my account.
What could be the problem here, am I using wrong resource name (/me/events) or this is some limitation for personal accounts in Microsoft Graph?
When you use /me/events you are going to the default Calendar for the user (per the docs). In your case, you would want to enumerate the user's calendars (GET /me/calendars) then subscribe to each one's events collection, using the resource /me/calendars/{calendar-id}/events.

Simplest way to display upcoming events from a public Google calendar?

I have a public calendar on the site. I need to display upcoming events on the front page.
After spending the whole day on this I am about to give up. Google is disabling older API there is no documentation or anything. I am parsing the RSS feed:
http://www.google.com/calendar/feeds/.../public/basic?futureevents=true
And grabbing feed/entry/update and feed/entry/title from XML. I read somewhere that futureevents will display upcoming events. However I get the list of older events.
Okay, then I tried to use API V3 https://developers.google.com/google-apps/calendar/v3/reference/events/list
Here is the responce I get:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
I jumped through more hoops and installed their ruby code sample as I need this for Rails site.
It sort of worked but it requires user to confirm access to their own calendar. I don't need that. Plus it seems that authentication only valid for a day.
The said calendar is public. It is being displayed in iframe on the site with xml and ical feed. All I need is to parse upcoming events to show them on front page.
What is the way to do it without authorization and other ridiculous stuff?
//This works for me! js:
var request = gapi.client.calendar.events.list({
'calendarId': 'xxx',
'timeMin': (new Date()).toISOString(),
'showDeleted': false,
'singleEvents': true,
'maxResults': 1,
'orderBy': 'startTime'
});
request.execute(function(resp) {}
Use this wizard to create a new API project: https://console.developers.google.com/start/api?id=calendar Then click on "create new key" (choose server key). Then do a request to https://www.googleapis.com/calendar/v3/calendars//events?key={YOUR_API_KEY} replacing the email and api key with your values.

Resources