Using Client Credentials with Microsoft Graph OneNote API on Office 365 Business - microsoft-graph-api

I am building an app (HTTPS calls from LabVIEW) that will update my enterprise OneNote notebooks on Office 365 without the need for any user interaction. Hence I have opted for using the Client Credentials flow and granting Application permissions in Azure AD to my app (Read and write all OneNote notebooks) through Microsoft Graph.
I have referred to the instructions mentioned in the following pages:
https://msdn.microsoft.com/en-us/office/office365/howto/onenote-auth-appperms
https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference
https://learn.microsoft.com/en-gb/azure/active-directory/develop/active-directory-v2-protocols-oauth-client-creds
https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service
https://developer.microsoft.com/en-us/graph/docs/concepts/onenote-create-page
I am able to get an access token from Microsoft Graph but once I try to use it to update my notebooks by making a POST call to the URL
https://graph.microsoft.com/v1.0/me/onenote/pages
I get the error:
"The OneDriveForBusiness for this user account cannot be retrieved." Code - 30108
However, I am fully able to access OneDriveForBusiness online using the same account which created the app and the tenant ID of which I used to grant permissions. Can someone please clarify if there are certain restrictions regarding the type of O365 and OneDriveForBusiness subscriptions that are necessary for my requirements? Which particular subscription or their combinations thereof should allow me to achieve the flow I need?

You cannot use /me with Client Credentials. /me is an alias for /users/{currentUserId but since you're using Client Credentials, there is a User in context for the API to map that alias to. You are effectively calling /v1.0/users/NULL/onenote/pages in this case.
You need to explicitly specify the User you want to access:
/v1.0/users/{userId or userPrincipalName}/onenote/pages

Related

User Consent to read Outlook/Teams/Sharepoint using Microsoft Graph API

I have to read User emails (particular subfolder), One Drive, Team Channels and Sharepoint after some regular intervals at the background using Microsoft Graph API but not without having the user consent which should be taken only once when they logged in to the web based application first time and not afterwards. I am not sure where to start from and how this can be achieved? Should the token be stored forever in some database securely OR Is it the AAD?
Would really appreciate any pointers/APIs/Libraries/concepts or links which can help in moving towards this direction.
If you want to get the token without user, client credentials flow can be used. The flow permits a web service (confidential client) to use its own credentials, instead of impersonating a user, to authenticate when calling another web service.
In the client credentials flow, permissions are granted directly to the application itself by an administrator. So it is necessary to use the application permissions. You could call Microsoft Graph API with the access token.
For example, call this API to get message:
You need to add one of the application permissions to API permission(navigate to Azure Active Directory-> your application), and click grant for your tenant.

"The tenant for tenant guid ... does not exist" when using client credentials flow (daemon) to access Microsoft Graph API

I want to access Microsoft Graph periodically from a console application in order to copy messages from an Outlook mailbox to a database.
In order to authenticate programmatically, I had to use the Microsoft Graph's "Client Credentials Flow".
These are the steps I had to take:
Register an App in the Azure portal and create a Client Secret for it.
Add all the permissions I need and grant them access:
Have an Admin confirm those permissions by accessing it for the first time. This is done using the following URL:
https://login.microsoftonline.com/{tenant}/v2.0/adminconsent
?client_id={app id}
&state=1234
&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient
&scope=https://graph.microsoft.com/.default
I received the following response:
admin_consent: True
tenant: ca566779-1e7b-48e8-b52b-68**********
state: 12345
scope**: scope: https://graph.microsoft.com/User.Read https://graph.microsoft.com/.default
(The scope might explain the problem described later here: Why do I only get User.Read when I've configured 13 different permissions??)
Get an access token (with success!):
Try to read users (with success):
Try to read my own emails (without success):
Try to read somebody else's emails (the user was invited to access the app as a guest, but still, no success):
I don't understand why I can't read Messages but I can read Users. It seems the permissions were completely ignored (I confirmed that I don't need any permission to read the users).
UPDATE
This is my tenant name:
These are the users added to the tenant:
Important: I don't own an office 365 subscription in my Azure AD. All these emails belong to a different AD.
The previous question "The tenant for tenant guid does not exist" even though user is listed on users endpoint? is similar to mine but I believe this is not a duplicate as my problem is slightly different and the proposed solution uses OAuth1 (I am using OAuth2).
Microsoft Graph can only access data within the tenant you have authenticated to. This means that you cannot access a mailbox from another tenant, even if that User is a guest in the tenant you authenticated to. Allowing this would violate the fundamental principle of data isolation in AAD/O365 tenants.
It is also important to note that AAD/O365 and Outlook.com are distinct platforms. Microsoft Graph's core value prop is a common API layer across AAD and MSA, but under the covers, they are calling into distinct backends.
Beyond data isolation and these being distinct platforms, Outlook.com simply does not support Application Permissions (Client Credentials). You can only access Outlook.com using delegated permissions, and even only a limited set of scopes are supported:
Not all permissions are valid for both Microsoft accounts and work or school accounts. You can check the Microsoft Account Supported column for each permission group to determine whether a specific permission is valid for Microsoft accounts, work or school accounts, or both.
With regards to which scopes are included, I suspect the issue here is that you don't have a license for O365 in this tenant. If it allowed you to consent without a subscription, this could (in theory) lead to apps unexpectedly receiving consent when/if a subscription got added later. That said, it is hard to tell without seeing an example of an actual token you're getting back (feel free to post one of you'd like me to look into this more).
Finally, juunas is also correct with regards to /me. The /me segment is an alias for "the currently authenticated user". Since you are not authenticating a user when you use Client Credentials, /me is effectively null.
/me won't work with a client credentials token.
What would /me refer to? There is no user involved so it cannot mean anything.
For the second problem, does this user have an Exchange Online mailbox in your tenant?
The accepted answer is the one that helped me out. However, I ended-up testing what I needed to test joining the :
Office 365 Developer Program (free)
This program will allow you to create an Azure Active Directory with up to 25 email accounts. It also allows you to create 16 fictitious email accounts with emails inside (by clicking one single button). You can use this infrastructure for 90 days for free.

Tenant does not have a SPO license

I have an error while trying to use Microsoft Graph to write a script to upload an Excel file to OneDrive then read the Excel file.
I followed Microsoft documentation to obtain the access token without user. I successfully got an access token but I got an error while using the access token to call the OneDrive API.
Here is the response:
{
"error": {
"code": "BadRequest",
"message": "Tenant does not have a SPO license.",
"innerError": {
"request-id": "5ec31d17-3aea-469f-9078-de3608f11d0d",
"date": "2017-10-10T04:34:05"
}
}
}
I don't understand why I need to have SPO license while calling graph API and how to get it. Because of this error message so I'm trying to buy a SPO license.
According to this document, I think I should see many products in the license pages but while logging in with Azure Portal and go to the License page, I see only 2 products: Azure AD Premium and Enterprise Mobility Suite:
In case anyone else has a similar issue, I was getting the same error message when using an Office 365 Home license. It turns out SPO stands for SharePoint Online, and you need an Office 365 Business account to have it. So as far as I can tell, you can't use the Microsoft Graph API to access OneDrive without having SharePoint (which only comes with the business licenses). This isn't really made clear anywhere that I could find.
Answering a couple of things here.
Background: Microsoft Graph is the developer gateway or API to many Microsoft cloud services, like Office 365, Azure Active Directory, EMS (Enterprise Mobility Suite), personal Outlook, personal OneDrive and more. Use of the API is free, but to access the data behind it, you need to actually have those services - in some cases they may be free and in other cases you may need to pay for them.
As for adding Office 365 to your existing tenant. I believe you've signed up for Azure using a Microsoft Account. This means that you already have an Azure Active Directory tenant. You can still purchase/acquire Office 365 for that tenant. All you need to do is create a new Azure AD user (not a Microsoft Account) in your tenant, and make them a company admin. Then you should be able to sign-up for Office 365 - if it asks if you already have a tenant or account, sign in with the AAD account you just created. And voila, you should have an Azure AD tenant with a subscription to Azure AND now a subscription to Office 365.
Hope this helps,
In case anyone else has a similar issue, I was getting the same error message when using a personal Microsoft account, just like OP.
So, if you are using a personal account in a registered Azure Active Directory(AAD) app, that type isn't Personal Microsoft accounts only or Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox) you will get this error. Also, you need to use the correct endpoint to avoid errors.
The main problem is our account type. As a personal account, there are some restrictions to access one drive files. These restrictions are:
You can only use Oauth2 Code Flow or Oauth2 Token Flow. Both are interactive approaches. [1][2]
Your application registered in AAD needs be Personal Microsoft accounts only or Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox) and each one have a different endpoint to acquire the access token (That you can saw clicking on endpoint button, near the delete app button in app page). [3]
Enable these delegated permissions to your application registered in AAD: Files.Read, Files.Read.All, Files.ReadWrite, and Files.ReadWrite.All.
With these restrictions in mind, you can set up a workflow in Postman following these two steps(I'm using endpoints of Personal Microsoft accounts only app type and using Oauth2 Code Flow):
Important note: To use code flow, you need to enable Access tokens in Implicit grant and hybrid flows on Authentication ADD app sidebar menu.
Aquire access token:
https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=YOUR_CLIENT_ID&response_type=token&redirect_uri=ONE_OF_REGISTERED_REDIRECT_URI&scope=Files.Read Files.Read.All Files.ReadWrite Files.ReadWrite.All
After you fill in your information on Postman's request, I recommend using a browser and network inspection to login with a Microsoft account and permit the app. You are getting the access token via network inspection.
List one drive root files:
https://graph.microsoft.com/v1.0/me/drive/root/children
Add a new header:
Authorization
With value:
Bearer ACCESS_TOKE_OF_STEP_1
In my angular application, due to this interactive way restriction to access one drive files, I changed my authentication method to use Microsoft Authentication Library(MSAL) to avoid every time that need send an API request open a popup window to authenticate a valid Microsoft account.
Both OneDrive for Business and the Excel APIs require Office 365. Based on your screenshot, this looks like a standalone Azure Active Directory tenant (i.e. not linked to O365).
The reason for the SPO License message is that OneDrive for Business is a special SharePoint Online document library that is automatically provisioned for users.
Are you able to access the OneDrive contents (including the Excel file) manually through browser after logging in with your account in the same tenant?
If you are able to access the drive and file manually, please use Graph Explorer https://developer.microsoft.com/en-us/graph/graph-explorer to sign in using the same account and make the call to get the Drive contents. When you’re signing-in, you would be presented with a consent page listing the permissions needed to be granted. Please make a note of those permissions and check whether the permission match to those required for accessing the drive.
If you do not have appropriate SPO license yet, you can try setting up a free Office-365 trial account (https://products.office.com/en-in/business/office-365-enterprise-e3-business-software) and test the APIs.
To add to Kikutos' answer answer, you can use this Azure sample to acquire the token via MSAL.NET.
The only thing you need to change is the Instance property, which needs to be set to:
https://login.microsoftonline.com/consumers/

Microsoft Graph API with Azure User Provisioning

What I want to do is quite simple: provision Office 365 and Azure Account from my Web App. And I want it to be available not only for me but for all the IT Departments (from other organizations too) that logs in my App.
From my understanding the steps I have to take are:
Register App on apps.dev.microsoft.com and get ID And Secret.
Enable the Scopes I'm interested in (in my case Directory.ReadWrite.All and User.ReadWrite.All) -- Enabled from both Delegated Permissions and Application Permissions
Gone through the LOGIN PROCESS
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=[My Client]&response_type=code&redirect_uri=[My Account]/Account/Office&response_mode=query&scope=openid%20User.Read%20offline_access%20Directory.ReadWrite.All
Confirm the code I receive back on my Return URL
POST https://login.microsoftonline.com/common/oauth2/v2.0/token?...secret and so on...
Now what I get is an object with Access Token, Renew Token and so on and so forth.
If I use it to get users, it's all working:
https://graph.microsoft.com/v1.0/users
But when I try to perform other operations the token seems invalid.
For instance:
Get Azure subscriptions (the account is admin of several subscription):
https://management.core.windows.net/subscriptions ==> UNAUTHORIZED
What I'm doing wrong? Is the IDEA behind it correct?
I really need to be done at a "global" level without config manual steps on every subscription or putting in some "TenantID" manually.
You've requested a token with scoped for the Microsoft Graph API which is why you can use API endpoints surfaced by https://graph.microsoft.com/.
The call to https://management.core.windows.net/subscriptions is not part of Microsoft Graph API so you're token isn't valid for that resource. That call is into the Service Management REST API. Authenticating for this API is documented here.

Accessing Calendar, Mail and Contacts of an OAuthenticated user

I configured an application on AzureAd to be multi-tenant, I chose to require all the permissions for Windows Azure Active Directory and Office 365 Exchange Online.
I can get a user to grant permissions, get access tokens, refresh them, OAuth works for me. I always used the "common" keyword instead of the tenant ID, because my app is multi-tenant.
Now, I would like to have (CRUD) access to a user's Mail, Contacts and Calendar with this token. Here is my problem: I am completely lost in all the possible API endpoints. Should I use: graph.windows.net, outlook.office365.com, graph.microsoft.com? This page seems to suggest that graph.microsoft.com is the Swiss army knife that would serve my purpose, but somehow I cannot find a doc that allows me to find the info I'm looking for. Plus, it seems under development and maybe too incomplete for what I want.
If I make queries against outlook.office365.com, I've got a 401 error.
If I put my access token in this token analyzer, it seems healthy although the scope field only shows the permissions I set in the AzureAd portal for Windows Azure Active Directory, not Office 365 Exchange Online.
I am kind of lost, any help would be welcome...
You have a choice:
Call the separate service apis - Your problem is that you acquired a token to call AAD, and then tried to use that to call Outlook - you need to make a separate call to acquire a token for outlook.office365.com through ADAL or through the token endpoint directly. The token acquired for AAD Graph can ONLY be used against AAD Graph. Similarly the token acquired for Outlook can ONLY be used against Outlook APIs.
Just to clarify - Azure AD OAuth can protect/secure multiple web APIs, including O365 APIs, Azure AD Graph, Azure Resource Management APIs, your own APIs and the new O365 unified API. In the first access token request, you specify the first resource you want/need to call. It doesn't have to be AAD Graph - i.e. it's not the default AFAIK. Based on what is consented to, you have the ability to request additional access tokens using the (multi-resource) refresh token. Vittorio's blog post which you link to in your comments does a great job explaining this.
Call the O365 unified API (which is in preview) and IS documented. See below. The beauty of the unified API is that you only need to acquire a token to call graph.microsoft.com and ALL the entities on that endpoint are available to you AND more. It removes the siloed nature of #1, and the requirement to get and manage multiple access tokens to call these different API endpoints. However #1 is currently GA, and the unified API is preview only at this time.
For more on #2 please see https://msdn.microsoft.com/en-us/office/office365/howto/office-365-unified-api-overview and search for "unified" in the list of samples here: https://msdn.microsoft.com/en-us/office/office365/howto/starter-projects-and-code-samples
We are working on improving the unified API documentation. If you are making pure REST calls, then I recommend starting out with the API explorer (and try things like https://graph.microsoft.com/beta/me/events and https://graph.microsoft.com/beta/me/messages to get your calendar events and mail messages), OR the API sandbox (which can show you JS code snippets, and allow you to test your own easily enough). As you can see on the REST examples, to access mail and calendar features in the unified APIs, you should be able to swap the service roots from Outlook to the unified API ie - https://outlook.office365.com/v1.0 -> https://graph.microsoft.com/beta. On the JS sample - we will be adding more capabilities here and additional samples.
NOTE: Personal contacts available in outlook.office365.com are not available in the unified API yet.
Hope this helps

Resources