Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Getting Access Token for Microsoft Graph Using OAuth REST API, Part 1

DZone's Guide to

Getting Access Token for Microsoft Graph Using OAuth REST API, Part 1

In Part 1 of this series, we look at the security protocols involved in this series, such as access tokens, and set up our OAuth application.

· Security Zone ·
Free Resource

Discover how to provide active runtime protection for your web applications from known and unknown vulnerabilities including Remote Code Execution Attacks.

Microsoft Graph is here to unite Azure and Office 365 data under a single roof. It is a simple REST API and Microsoft provided many examples of how to use it, including an interactive Graph Explorer which allows us to discover the different methods.

Using the API is as simple as sending an HTTP request - for example, calling this method will return the details about the users in the directory:

https://graph.microsoft.com/v1.0/users

In the Graph Explorer demo page it all works fine, but as soon as we try to use the Graph API from outside the page, from another program or test application like Postman, we receive a "401 Unauthorized" exception.

What's the deal?

The Access Tokens

As it turns out, in order to use any of the Microsoft Graph API, we need to let it know who we are - who is making the request.

Microsoft Graph API uses Bearer Authentication in order to validate the request, which means it expects to receive an authorization token (sometimes called a bearer token) together with the request. This token will contain, in a secured way, all the details about the requester.

Sending an authorization token with the request is a simple matter, all we need to do is to add an Authorization header to the request containing the word Bearer and our authorization token:

Authorization: Bearer <access_token>

There are several kinds of authorization tokens – Graph API requires an access token. The token itself is a looks like a random base 64 string, something like:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI3Rlcy5SZWFkLkFsbCBOb3..
QXBwIG9mZmxpbmVfYWNjZXNzIG9wZW5pZCBQZW9wbGUuUmVhZCBQZW9wbGUuUmVh..
ZC5BbGwgcHJvZmlsZSBSZXBvcnRzLlJlYWQuQWxsIFNpdGVzLkZ1bGxDb250cm9s..
LkFsbCBTaXRlcy5NYW5hZ2UuQWxsIFNpdGVzLlJlYWQuQWxsIFNpdGVzLlJlYWRX..
DMrCzi7JrvQ7_jclKHfPrv7jJAgsHfYkal5OalQAWRC6kaj6cgO0c7xyfGQUnhGA

It is not important to understand the token format for now, only that once we get a valid access token we can use it to access the information we need.

So how do we get the access token? That's where things get little more complicated.

In order to get a valid token for the Graph API, we need to use another Microsoft API: the Azure Active Directory (AAD) Services.

Azure Active Directory Services

Azure Active Directory is where all of our organization's users are stored. Since the data we want to retrieve from the Graph API is usually related to specific users, it only makes sense that we need to use Azure Active Directory Services in order to retrieve a valid access token.

Microsoft AAD Services is based on the OAuth 2.0 protocol and act as an Identity Provider, which is an OAuth term for "where the users sit." Using these services, we can issue access tokens for the Graph methods (as well as id tokens and refresh tokens which are not in the scope of this article).

The Azure Active Directory Authorization endpoint has the following URL format:

https://login.microsoftonline.com/<organization-directory-name>.onmicrosoft.com/oauth2/token

Meaning every tenant directory has its own URL. The directory name can be found by hovering over our name in the Azure Portal.

Instead of a name, we can also use the directory ID:

https://login.microsoftonline.com/256d2b4c-b5c3-758f-55f3-cd8969f04e86/oauth2/token

Your Azure Active Directory ID can be found in Azure Portal > AAD Properties blade:

So now that we know what the authorization endpoint URL is, what message do we need to send in order to get an access token?

Well, the answer for that is - it depends. The service supports several OAuth authentication flows, each suited for a different scenario and the kinds of information we have. Regardless of the kind of message we send, the response will always contain the Access Token.

But, before we can look at the different options, we first need to understand another important part of the puzzle. All of the different flows in Graph API have something in common - they all require a Client ID with a Client Secret. In order to get those, we first need to create an OAuth App.

Understanding OAuth Apps (Clients)

A very important concept in the OAuth world is the separation between users and clients. Users are the actual people who use our system. Clients are the applications they are using to do so. Why is this separation important? It's all about regulating access to resources.

In the past, when applications wanted to access data in another system or database which required authentication it had two options:

  • Pass on the current logged in user's authentication.
  • Impersonate a strong user.

Many times, the first option was not used - sometimes because it was complicated to perform (SSO is hard to get right), or the current user did not have enough permissions to perform the operation the application required.

This leaves the second option: impersonating a strong user. But which user to impersonate? Since we don't want to use an existing user (which could lead to many issues), a dedicated user for the application needs to be created. Those users are often called System Accounts since they are used by the system and not actual human beings.

However, this pattern of using system accounts had many problems, for example:

  • Password policy: The System Account had a password just like any other user, which caused problems if the normal password policy were applied to them. For example, the accounts would have locked after a number of failed login attempts (usually by entering the wrong password). Also, the password would expire after some time. In all of those instances, the user was automatically locked, meaning all applications which depended on them would have failed.
  • Managing: Users are usually managed by the organization's IT department, meaning developers were dependent on them in order to create and manage System Accounts across different environments. This can cause operation delays and unexpected application shut-downs as a result of a random password change.
  • Security: Since the application runs its code as a power-user, any vulnerability in the code could allow users to gain access to data they were not supposed to be able to access. This can be used for to perform Privilege escalation attacks. Because of that, it is usually considered dangerous to use code impersonation.
  • No refined Access Control: Since the application is using a single System User for ALL users, it means that System Account has to have full access to ALL of the user's data. This could lead to information leakage where users are accidentally exposed to other users data. Also, the users have no say in what kind of data a specific application can access - it is controlled by the system itself.

Because all of those issues, the OAuth protocol doesn't use System Accounts in order to authenticate a client program. Instead of System Accounts, we now have OAuth Apps (clients).

In OAuth, when a client application wants to access a resource (for example our Graph API), the first thing it needs to do is to authenticate itself (meaning which client application is calling the service, not which user is using it). This is done by sending the Client ID and it's matching Client Secret.

So where do we get that Client ID and Secret? We can get it by registering an OAuth app.

Registering an OAuth App

We can register an OAuth app for the Graph API from the Azure Portal.

Full instructions on how to do so can be found in the official documentation here.

For our needs, this is the minimum which is required:

  1. Create a new app in the target directory (Azure Portal > Azure Active Directory > App Registration > New Application Registration).
  2. In the Create screen, enter the following information:
    • Name: Can be any name, for example, "MicrosoftGraphClient."
    • Type: Must be "Web App/API" for our needs.
    • Sign-On URL: Not important (since we do not intend users to directly login to the app), for our case, we should put it under the tenant directory. For example,https://<directoryname>.onmicrosoft.com/MicrosoftGraphClient
  3. Get the Client ID: Note the Application ID - It is the Client ID, so we need the following steps.
  4. Create a new Client Secret: Navigate to App > Keys > Passwords and add a new key.
    • Name (description): enter a descriptive name for the key so you later know that the client application is using it (you can have more than one key per app).
    • Expires: Choose "Never Expire," unless you want to change your key every year or two.
    • Click Save - a new Client Secret will be generated for you. This will be the only time you will see the Client Secret, so you better copy it to a secured location otherwise you won't be able to retrieve it again!

Configuring App Permission

Now that we have created an app, we have to configure its permissions. In the OAuth world, when apps try to access information, they must have the appropriate permissions to do so. Configuring those permissions is a two-step process - first, we need to declare what kind of permissions the app would like to have. Then we need to make sure the app is granted that permission.

  1. Setup app permission: Navigate to App > Required Permission > Add > Select an API > "Microsoft Graph" > Select Permission. We see a list of Graph related permissions. Here we can select the permission our app should have, according to the type of information it needs. If we are not sure about which specific permission is required, we can use the API Documentation to find out. For example, since we wanted to access the /Users method, we can find in the Users documentation page that one the permissions which will allow us to call this method is User.Read.All. There are two permission groups: Application Permission and Delegated Permissions, and many permissions exist in both groups. More on that later, for now, select the required permission in both groups.
  2. Grant App permissions: Now that we have declared what kind of permission our App requires, it's time to grant them to the App. Usually this is done by the user when the app first attempts to access their information, but, for now, we can just "accept" on behalf of all of our tenant users by doing one  of the following:

    a. Clicking the Grant Permissions button in the App > Required Permission section:    b. Using the admin consent endpoint


https://login.microsoftonline.com/{TenantDirectory}.onmicrosoft.com/adminconsent?client_id={ApplicationID}

In both cases, we end up granting our app the required permissions for all of the users in the directory.

Note: Consenting on behalf of all users is usually only done in specific scenarios, like a background service which requires full access to all tenant data. In most cases, users should consent themselves.

That's all for Part 1, tune in tomorrow when we'll begin to discuss how to get your access tokens, and a few of the flows involved. 

Find out how Waratek’s award-winning application security platform can improve the security of your new and legacy applications and platforms with no false positives, code changes or slowing your application.

Topics:
oauth 2.0 ,azure active directory tokens ,json web token ,security ,api security

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}