The hardest and most critical component of working with Microsoft Graph API is AUTH – Authentication, and Authorization that you need to take care of, for your app/script to be able to make successful API calls.
Today in this blog post, we will try to uncover and understand the AUTH mechanism of the Microsoft Identity platform to successfully work with Microsoft Graph API.
Table of Contents
Context
Welcome to the 2nd post of the series Learn How to Use Microsoft Graph API with Joy that I started with my previous blog post, where I talked about how you can get started with Microsoft Graph API using Graph Explorer.
As I have mentioned there, though Graph Explorer happens to be a good tool/application to get acquainted with MS Graph API, it does not let you make API calls programmatically.
Thus, if you intend to use Graph API to
- automate workflows, or
- provide customized user experience for your users via a custom app, or
- establish service-to-service integrations
you have to resort to using either
- a programming language of your choice to create/build an application, or
- a scripting language of your choice.
But before getting started with programming/scripting API calls to Microsoft Graph, it is important to understand the permissions/authorization types that Microsoft Graph API supports and based on the permission/authorization type, the different authentication flow methods that you need to incorporate in your app (program/script) to get started with.
This blog post aims to help you with exact the same.
Why it is important to understand Auth to work with MS Graph API?
Consider you have built your custom app or you have created a PowerShell script to automate a workflow.
In order for your app/script to successfully make API calls to Microsoft Graph, it requires your app/script to authenticate to and get an Access Token with which it can make the API calls you have defined.
Microsoft Graph uses the same Microsoft Identity (MSAL) platform for Auth – OAuth and OpenID Connect.
The Access token contains information (claims) that web APIs secured by the Microsoft Identity platform, such as Microsoft Graph, use to validate the caller/client and to ensure that the caller/client has the proper permissions to perform the operation(s) they’re requesting.
Why it is required to register your application with Azure AD?
For your app/script to get Access token(s) from the Microsoft Identity service, it must be registered in your Azure tenant.
This is because, when you try to authenticate using your app, the authentication request as sent by your application also contains the client (app) information that the authentication endpoint (Microsoft Identity service) uses to validate the request.
Azure AD App Registration integrates your app with the Microsoft identity platform and establishes the information that your app uses to get Access tokens.
The information that we are talking about is
- Application ID – Unique GUID assigned to the app by Microsoft Identity service to help identify the app.
- Application Secret – A password or self-signed certificate that your application uses to authenticate itself to the Microsoft Identity service.
Is authentication enough to work with Microsoft Graph API?
Successful authentication does not guarantee that your app/script will work.
This is because Microsoft Graph also requires to have the permissions consented to (authorization to access) for the resources that the API calls in your app/script are trying to access.
Thinking it’s too complex? Let’s take an example and make it easy for all to understand.
When using Graph Explorer, the tool itself takes care of auth via an interactive user sign-in to retrieve the access token from the service.
The application runs impersonating a signed-in user and as such works only with user-level permissions. You can add the permissions required as shown below.
If the permissions has not been consented already, you will be prompted to provide consent for the required permissions added.
Note the option to Consent on behalf of your organization. Microsoft Identity platform can detect if the user performing sign-in is a Global Admin and shows the option if the person would want to consent the permissions for all users of the tenant. As a note, in your app/script, you can also use the dedicated admin consent endpoint to proactively request an administrator to grant permission on behalf of the entire tenant.
Once you sign-in succesfully, you can view the Access token from the Graph Explorer console.
Further debugging the access token, you will find that, among all the other different details, it contains the below listed important details
- Token Issuer [iss]
- Token issued time [iat]
- Token validity details [nbf and exp]
- Application details you are using to work with Graph API [app_displayname and appid]
- Identity type [idtyp]
- The signed-in user details [name, oid, upn]
- The permissions that are currently consented for the app [scp]
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/13b9b587-b500-49e8-a36f-c34aa188c4db/",
"iat": 1616243772,
"nbf": 1616243772,
"exp": 1616247672,
"acct": 0,
"acr": "1",
"acrs": [
"urn:user:registersecurityinfo",
"urn:microsoft:req1",
"urn:microsoft:req2",
"urn:microsoft:req3",
],
"aio": "AZQAa/8TAAAXoTQoZiTfAnTpNVNVTYAWasoHClsAHRbtoEhvAuh/U15lpArHb/3c++eVjeM8",
"amr": [
"pwd",
"mfa"
],
"app_displayname": "Graph explorer (official site)",
"appid": "de8bc8b5-d9f9-48b1-a8ad-b748da725064",
"appidacr": "0",
"idtyp": "user",
"ipaddr": "45.113.91.26",
"name": "JOYMALYA BASU ROY",
"oid": "755bfdca-192c-4aa2-a943-a2dcc0f76d72",
"platf": "3",
"puid": "100320011CAC59E5",
"rh": "0.ARAAh7W5EwC16Emjb8NKoYjE27XIi9752bFIqK23SNpyUGRwAGk.",
"scp": "Calendars.ReadWrite Contacts.ReadWrite DeviceManagementApps.ReadWrite.All DeviceManagementConfiguration.Read.All DeviceManagementConfiguration.ReadWrite.All DeviceManagementManagedDevices.PrivilegedOperations.All DeviceManagementManagedDevices.Read.All DeviceManagementManagedDevices.ReadWrite.All DeviceManagementRBAC.Read.All DeviceManagementRBAC.ReadWrite.All DeviceManagementServiceConfig.Read.All DeviceManagementServiceConfig.ReadWrite.All Directory.AccessAsUser.All Directory.ReadWrite.All Files.ReadWrite.All Group.ReadWrite.All IdentityRiskEvent.Read.All Mail.ReadWrite MailboxSettings.ReadWrite Notes.ReadWrite.All openid People.Read profile Reports.Read.All Sites.ReadWrite.All Tasks.ReadWrite User.Read User.ReadBasic.All User.ReadWrite User.ReadWrite.All UserAuthenticationMethod.ReadWrite UserAuthenticationMethod.ReadWrite.All email",
"sub": "0AQhLVcxzVXst6_wq3bpHIG6ZMGJJibhu2C7ZUTR0LI",
"tenant_region_scope": "AS",
"tid": "13b9b587-b500-xxxx-yyyy-c34aa188c4db",
"unique_name": "joymalya@intunewithjoy.in",
"upn": "joymalya@intunewithjoy.in",
"uti": "UsXSH9U390mOB8XTfuwdAA",
"ver": "1.0",
"wids": [
"b79fbf4d-3ef9-xxxx-yyyy-76b194e85509"
],
"xms_st": {
"sub": "K8LMDaa1w6-Geyg6AUzv2tgonsxEshXdI"
},
"xms_tcdt": 1568191721
}
For Microsoft Graph, every resource in itself is treated as a secured entity and as such requires permissions (authorization) to be granted to the application to access the same via API calls.
Running a Graph API query without having the required permission (authorization) will always result in query failure as shown below.
I hope that now you have an idea about the importance of Authentication and Authorization (Permissions) to work with Microsoft Graph. Let’s now move on to understand the types of permission (authorization) that Graph API supports and the authentication methods that you can use for each authorization type.
Understanding Microsoft Graph API Permission types
Microsoft Graph API supports the below Permission (Authorization) types
Authorization/Permission Type | Description |
Delegated | Used by apps that have a signed-in user present and impersonates the signed-in user when making calls to Microsoft Graph. Effective permissions of the app will be the intersection of the delegated permissions the app has been granted (via consent) and the privileges of the currently signed-in user. The app can never have more privileges than the signed-in user. Thus effectively this permission type requires you to use either Authorization code or Username/Password [ROPC] auth flow, since these are the two that involves user sign-in. |
Application | Used by apps that run without a signed-in user present. Effective permissions of the app will be the full level of privileges implied by the permission. Thus effectively this permission type requires you to use Client Credential auth flow since it performs sign-in based on app identity and does not involves/requires a user sign-in. |
Remember that some Graph API resources can be accessed with only Application permission type, while some can be accessed with only Delegated permission type, whereas the majority can be accessed using either of the two permission/authorization type.
Reading the descriptions of the two, it is easy to understand that authorization/permission type Application has more privilege than Delegated, since for permission type Application, effective authorization will be the full privileges as implied by the permissions consented.
As such you will see in Graph documentation, for any resource, it always charts the required permissions from least (Delegated, work account) to most privileged (Application).
Use the Microsoft Graph beta and v1 reference documentation to identify the permissions required for the particular resources that your application (program/script) would be working with. Again, a security best practice is to try using the permission with the least privilege.
Understanding Scope
Scope is a mechanism in OAuth 2.0 to limit an application’s access.
When an app requests permission to access a resource through an authorization server, it uses the scope parameter to specify what access/permissions it needs and hence determines what resource(s) will be available for access when the Access Token is used by the application to access any protected resource.
Microsoft Graph permission names follow a simple pattern: resource.operation.constraint
.
If no constraint is specified, then the app is limited to performing the operation on the resource that is owned by the signed-in user.
For example, from the above snapshot, with the permission
UserAuthenticationMethod.Read
– the application would only be able to read the authentication methods available for the signed-in user, i.e. the user account that the app is running on-behalf.
UserAuthenticationMethod.Read.All
– the application would be able to read the authentication methods available for all users present in the directory.
This is a way to create a smaller subset of permissions for a resource in order to have better control over the access and action that can be performed on its data.
As a best security practice, when requesting scopes for your app/script, ensure to ask only for enough access for the app/script to function properly, requesting permissions only what is absolutely needed.
For example, if your application needs to only retrieve user data, but will not modify it, then it only needs the permission User.Read.All
. As a developer, you can code the app to only request for this particular permission with the help of the scope parameter.
$Scope = "https://graph.microsoft.com/user.Read.All"
Note that an application while authenticating can also request for multiple scopes like this
$Scope = "https://graph.microsoft.com/user.Read.All https://graph.microsoft.com/UserAuthenticationMethod.Read.All"
The above is an example of dynamic scopes. We can also declare a static scope as shown below
$Scope = "https://graph.microsoft.com/.default"
This means that whatever permissions you have listed during the app registration in Azure, including both delegated permissions and application permissions, when you are making an auth call using the static scope /.default
, you are requesting for all of that.
It is to be noted that you cannot use both static and dynamic scopes in the same auth call. Also, if your app requires Application type permission, it can only be requested using the /.default static scope.
The access token received post-authentication will contain only the permissions with which the authentication request was made [or, the permissions which was consented for the app to use at the time of auth is using /.default scope]. Any modification of API permissions post-authentication will take effect when the app will renew its current access token.
Why do we need to know about different MSAL auth flows?
In order to work with the different permission types (Delegated/Application) as supported by MS Graph API, you need to know about the different supported MSAL auth flows, because not all the auth flow methods can work with both the permission types.
The method of auth flow that you choose to use must match the authorization/permission type, especially if the authorization/permission type is Delegated.
This is because if your app is granted delegated permission, means it requires the app to run by impersonating a signed-in user. However, if your app does not require a signed-in user to run, but is assigned with delegated permissions, it will not work and instead, the API calls made by the app will return with HTTP Authorization error.
As such, it is important to assess the use-case, whether the app requires to run impersonating a user or by itself, and based on the same, use the appropriate permission type and the authentication method.
Note that there are different MSAL supported OAuth auth flows, however for the purpose of this blog series, I will discuss only the two most common MSAL (OAuth2) auth flows that are used to work with Microsoft Graph API.
MSAL Auth Flow Method: Authorization Code
This auth flow is used in apps that requires a user sign-in to work and as such is not suitable for autonomous automation. It is used in cases where the app must act by impersonating a user account due to audit or security requirements.
This auth method involves an interactive user sign-in.
The application sends the auth request which includes the user credentials retrieved from the user via an interactive prompt, along with its information (client information) to the auth endpoint. The auth endpoint validates the auth request and sends back an authorization code which the app then redeems to get an access token, with which it then accesses the protected resources.
This auth flow is best suited for use with Delegated permissions.
MSAL Auth Flow Method: Client Credential
This auth flow method is commonly used in scenarios where the app runs autonomously in the background without requiring any user interaction, and as such makes it the most suitable auth method to use for purposes that require complete unattended automation.
As the app does not requires to work by impersonating a user account, as such this auth flow does not involve any user sign-in. Instead, the app works by using its own credentials obtained by virtue of Azure AD app registration.
The application acquires access token from the auth endpoint by using either a confidential application secret or a self-signed certificate, which it then uses to access and work with the protected resources.
This auth flow is best suited for Application-level authorization.
Conclusion: Usecase of different Auth to work with MS Graph API
For the different Auth flow methods and the different Permissions type to work with Microsoft Graph, this is what we can draw as the conclusion based on use-case.
Auth Type | Permission Type | MSAL Auth Flow | Use-Case |
User Interactive | Delegated | Authorization Code | Scripts/Apps which runs impersonating a signed-in user. |
Silent (No User) | Application | Client Credential Client Secret | Scripts/Apps that can run unattended without requiring to impersonate a signed-in user. |
Silent (No User) | Application | Client Credential Certificate | Scripts/Apps that can run unattended without requiring to impersonate a signed-in user. |
Though this may not be exhaustive, I just tried to present the most widely used auth scenarios for MS Graph API.
To be contd.
Let’s keep it till this for today.
I hope this post helps you to give a clear picture of the intricacies of the authorization/permission types and the different authentication flows that you need to understand to be able to effectively work with Microsoft Graph API.
The next part of this blog series will show you how you can implement the knowledge gained from this blog post to get an Access Token using PowerShell to be able to make API calls to Microsoft Graph. Stay tuned!