5

I developed an Outlook Web Add-in that is working fine. It's a Taskpane that is available in compose mode of appointments and that collects event's data, adds a few ones and send that all to an API somewhere.

What I would like to do now is to subscribe the authenticated user to the Outlook Rest API in order to get notified when the event is deleted.

The subscription call should look like this one:

POST https://outlook.office.com/api/v2.0/me/subscriptions HTTP/1.1 
Content-Type: application/json 
{ 
  @odata.type:"#Microsoft.OutlookServices.PushSubscription", 
  Resource: "https://outlook.office.com/api/v2.0/me/events", 
  NotificationURL: "https://myNotifAPI.azurewebsites.net/api/send/myNotifyClient", 
  ChangeType: "Deleted", 
  ClientState: "blabla" 
}

I know I need to provide a valid Authentication Bearer Token when posting to the subscriptions URL so I tried to call this method in my Add-In:

_mailbox = Office.context.mailbox;
_mailbox.getUserIdentityTokenAsync(getUserIdentityTokenCallback);

In the function getUserIdentityTokenAsync, I call a WebApi Controller that validates my token and send it back to the Add-In:

AppIdentityToken token = (AppIdentityToken)AuthToken.Parse(rawToken);
token.Validate(new Uri(request.AudienceUrl));
return token;

I tried to use that token to Post to https://outlook.office.com/api/v2.0/me/subscriptions (using Postman) but I got a 401 saying:

reason="The audience claim value is invalid '<MyAddInURL>'.";error_category="invalid_resource"

Is it the right Token to use in that particular case or do I need to get another one? Any advices would be appreciated!

-- EDIT --

As suggested by @benoit-patra I tried to get a token using getCallbackTokenAsync instead of getUserIdentityTokenAsync but when I called https://outlook.office.com/api/v2.0/me/subscriptions I did receive a 403 :

"error": {
    "code": "ErrorAccessDenied",
    "message": "The api you are trying to access does not support item scoped OAuth."
  }

As requested by @benoit-patra here's the Token content :

{
  "nameid": "9d643d8c-b301-4fe1-83f7-bf41b1749379@57bcd3d9-685a-4c41-8c7d-xxxxxx",
  "ver": "Exchange.Callback.V1",
  "appctxsender": "https://localhost:44444/NewAppointment.html@57bcd3d9-685a-4c41-8c7d-xxxxxx",
  "appctx": {
    "oid": "3a8a4f92-a010-40bd-a093-xxxxxx",
    "puid": "10033FFF9xxxxx",
    "smtp": "max@xxxx.onmicrosoft.com",
    "upn": "max@xxxx.onmicrosoft.com",
    "scope": "ParentItemId:AAMkADE4NTk2MDNjLTI4NGEtNDZkNS1hMzg4LTE3MzI2NGJhZWRkZQBGAAAAAAD+YYA7CnMtRZsrwJ7l6m44BwCcSer9F+cXSrWNauuHQlZ7AAAAAAENAACcSer9F+cXSrWNaxxxxxxxx"
  },
  "iss": "00000002-0000-0ff1-ce00-000000000000@57bcd3d9-685a-4c41-8c7d-xxxxx",
  "aud": "00000002-0000-0ff1-ce00-000000000000/outlook.office365.com@57bcd3d9-685a-4c41-8c7d-xxxx",
  "exp": 1487087672,
  "nbf": 1487087372
}
MaxSC
  • 4,698
  • 2
  • 23
  • 36

2 Answers2

5

The previous answer is right, the error is because you are getting an item scoped token. Because previously Callback tokens only allowed a caller to call GetItem and GetItemAttachment REST APIs. We are making changes to the callback token so that clients can call REST of the APIs as well. The requirement is first you should have readWriteMailBox permission. Second get a REST callback token by providing isRest=true, like below

Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, function (result))

The resulting token will have Mail.ReadWrite, Calendar.ReadWrite, Contacts.ReadWrite, and Mail.Send Scopes.

That said the isRest parameter is only supported for outlook mobile client right now. The work to support it on OWA and Outlook is in progress and we expect to release it by March.

Davide Aversa
  • 5,628
  • 6
  • 28
  • 40
Sohail Z
  • 51
  • 3
  • thanks for the feedback. Any workaround you might think of waiting for the Outlook support to be released? – MaxSC Feb 14 '17 at 20:33
  • @MaxSC The work around would be to load the office.JS file from the dogfood environment. That change should be available within a week or so. I will include the link when its available – Sohail Z Feb 14 '17 at 22:41
  • Great, let me know as soon as it's available for testing! – MaxSC Feb 15 '17 at 09:27
  • Hi @sohail-z! Any news about the Office.js availability? Thanks! – MaxSC Feb 21 '17 at 12:37
  • For OWA its going to be available in couple of weeks and for outlook 2016 desktop by end of March. – Sohail Z Feb 24 '17 at 23:46
  • That's said, I for got to mention that the lifetime of a callback token is 5 mins so the add-in will have to get a new token every time. So a better approach would be to take the user through the AAD oAuth flow and use the resulting access and refresh token to make the call. – Sohail Z Feb 24 '17 at 23:47
  • Thanks for the feedback @sohail-z! I'm ok with 5min and I don't want the user to enter credentials (I guess it would be the case with AAD oAuth flow?) – MaxSC Feb 25 '17 at 09:14
  • Hello @sohail-z Any news to share? Thanks! – MaxSC Mar 23 '17 at 10:26
  • Just as a general remark: the `Office.context.mailbox.getCallbackTokenAsync({isRest: true}, function(result){` works now in Outlook 2016 Client. I dont know since when exactly (probably since march as suggested) but as of November 2017 I can say that this is working fine. – klaas Dec 01 '17 at 14:34
2

You should use getCallbackTokenAsync() this is the JWT that will give you the AccessToken that will help you authenticating for the Outlook REST API

https://dev.office.com/docs/add-ins/outlook/use-rest-api

For your case, following the documentation, I think you will need ReadWriteMailbox to have sufficient permissions to register web hooks with Outlook REST API.

NOTE: I tried this on my add-in, I changed the add-in permission to ReadWriteMailbox but the JWT token when inspected with JWT.io still has for scope:ParentId=<itemid> which I think won't work. Tell me if you have the same problem here.

Benoit Patra
  • 4,355
  • 5
  • 30
  • 53
  • Thanks a million @benoit-patra ! I literally search the web for such a link! I now feel ashamed :) Let me test that and I'll get back to you! – MaxSC Feb 14 '17 at 14:54
  • 1
    Ok, I gave it a try, but unfortunately the token returned by `getCallbackTokenAsync()` doesn't seem to give me the proper access rights to call `https://outlook.office.com/api/v2.0/me/subscriptions` as I did receive a 403 saying "_The api you are trying to access does not support item scoped OAuth_" – MaxSC Feb 14 '17 at 15:59
  • @MaxSC I think there is a bug the `getCallbackTokenAsync` when using with a `ReadWriteMailbox` addin should provide a JWT and then AccessToken with `scope` for more than just the currentItem which seems to be the problem. Can you provide what you see in your JWT (with real values obfuscated of course) – Benoit Patra Feb 14 '17 at 18:23
  • @MaxSC always a pleasure to help people from my home town Nantes^^ – Benoit Patra Feb 14 '17 at 18:24
  • I've edited my question with the Token content but @sohail-z said that this only works for Outlook Mobile right now. If you think of a workaround, I'm all ears! ;) Big up from Nantes ;) – MaxSC Feb 14 '17 at 20:40
  • Long awaited stuffs, seems wait is going to over soon :). Thanks to the community to consider this scenario because implementing another OAuth implicit authentication flow was pain for users. – Hitendra Feb 16 '17 at 09:23
  • Looks like that reference URL has changed. I got a 404 but found something here https://learn.microsoft.com/en-us/office/dev/add-ins/outlook/use-rest-api – Tom Resing Nov 03 '20 at 10:45