Microsoft Graph API with Azure User Provisioning - microsoft-graph-api

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.

Related

"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.

Daemon application gets an App-only access token with no Roles

I have a JavaScript app that requires a user to login and hit a button then it runs a report, posts data to Excel, and sends an email. I want to automate this so a user does not have to log in and push a button.
I started with this project code: https://github.com/microsoftgraph/nodejs-apponlytoken-rest-sample
I followed the instructions and am able to get an access token but then my api call fails with 401 unauthorized. As a test, I am trying to send an email as myself and I have the Application type Mail.Send permission granted by the company admin.
I have spent many hours reading docs and blogs but have not found a solution. This document summarizes best what I am troubleshooting: https://blogs.technet.microsoft.com/sharepointdevelopersupport/2018/03/15/troubleshooting-assistance-with-microsoft-graph-api-development/.
The token I get back does not have any Roles in it as seen when I decode it with JWT. This is the only discrepancy I have found so far.
Any advise would be greatly appreciated. How can I ensure that my token has Roles defined or what else can I try? How is it that I can get a token successfully but can't use it for anything?
Thank you!
I am not a Node expert, so helping you out with a few pointers that might help.
Microsoft Graph has two types of permissions, Delegated and Application. So some things to know of and check..
Delegated permissions require a user to be present, they would show up in the scp claim in the access token. These are obtained by web applications using the implicit_grant flow, Authorization code grant or on-behalf-of flow (usually).
Application Permissions, require an admin to consent and will be provided to you in the roles claim in the access token. This requires, the app to obtain an access token via the client credentials grant. Note that, these are also present when the user is assigned a role as explained in this sample, but this scenario might not be applicable for in your case.
Does you app has the grant provided as you expect? You can check these via the Graph Explorer using the following two rest calls. There would be a OAuth2PermissionGrant entry with the expected role in it.
https://graph.microsoft.com/beta/OAuth2PermissionGrants
https://graph.microsoft.com/beta/kalyankrishna.net/OAuth2PermissionGrants
It'd help more if you can explain the flow that you have been using to obtain the access token. For example, the implicit_grant_flow does not work with application permissions.
In my case, the problem had to do with the endpoint and my tenant. I had been using the common tenant make api calls for tokens because that is what was listed in AzureAD for my app. I found that for the Application client permissions I must use my specific tenant id like 'https://login.microsoftonline.com/tenant_id/oauth2/token' when getting tokens with the proper roles.

Using Client Credentials with Microsoft Graph OneNote API on Office 365 Business

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

invalid_client no registered origin for service account approach

I am trying to do Google API authorization through both Web Application approach and service account approach. For web application approach, the quick start code from their website works fine. However when I tried the same code with service account Client ID (same code as the quick start example, just replacing the Client ID), it gives me Invalid_client no registered origin error.
I saw in this post and other SO questions, mostly they forgot to put the Authorized Javascript Origin. However, this is different for service account approach, they don't have this field.
Anyone encountered same issue?
Error message: no registered origin
Request Details proxy=oauth2relay1086088613 immediate=false
scope=https://www.googleapis.com/auth/analytics.readonly
origin=https://localhost:9443 response_type=token
redirect_uri=postmessage state=909080772|0.2369183797
client_id=113356969233986791514 include_granted_scopes=true
Service accounts are typically used in server-to-server communication. You can think of a service account as a robot user that has permissions to access the API. Unless you're doing domain-wide delegation (where a service account can act on behalf of all users on a domain), you probably just want to use OAuth. Perhaps try the credentials wizard and see what it recommends?
If you do end up wanting to use service accounts, you'll need to download a private key for the service account and sign the request with that key (rather than just including the OAuth client ID). To do that, I recommend using one of the Google API Client Libraries.

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