Securing NodeJS REST with Azure Active Directory

You should be interested in this post if:

  1. You want to build a NodeJS application that provides resources and only resources via a REST API. I will refer to this as a Resource Provider hereinafter. Resource Provider can be deployed anywhere, Heroku for example. It can also be deployed on Azure, but doesn’t have to.
  2. You also want to protect or secure the resources of the above Resource Provider. Only authenticated users can access these resources.
  3. By uttering the phrase “authenticated users”, we’re talking “accounts”, we’re talking “passwords”. But you don’t want to write all that code to handle accounts, passwords, encryption, public, private keys, etc yourself. First reason: that is very, very hard to do. Second reason: Azure Active Directory (AAD) is already so good at doing this job. Let’s outsource this job to AAD. In other words, AAD is the Authorization Provider.
  4. BUT, in capital letters, not everything should be outsourced to AAD. You DON’T WANT users of your apps to ever be re-directed to the AAD Login and Signup pages. Microsoft allows only a very little customization to be done on those pages. You want total freedom. You have awesome designers so you want the Login and Signup pages to sport the design that your designers worked hard on. You want the Login, Signup, Reset Password pages to be coming from within your app, no pop up Safari, no pop up Chrome. You want to give your users the best possible User Experience.
  5. So now with the Resource Provider and with the Authorization Provider, you will want to write Client Apps. Client Apps are what your users feel and see. Client Apps consume the secured resources and can be an iOS app, an Android App, or a web application. In fact, your Client apps can be built in any language (Swift, Java, C#, JavaScript, etc) and can target any device.
  6. You have been so confused from reading plethora of articles on Azure Documentation Center.
  7. You want this to be the first and last time reading the word OAuth in this post. Trust me, that’s a buzz word that won’t help you at all, unless you want Facebook users, Twitter users to be able to login as well. Everything that we’ll do here will not prevent that capability if you so desire in the future. I just won’t discuss about that feature in this post.

If those are what you want, this post is absolutely for you. Talking about buzz words, JSON Web Token (JWT) is NOT a buzz word. You might want to read up on it. Just remember that JWT can be used independently from OAuth. Oops I just said that word. OK so that was the second and will be the last time it’s mentioned.

So how does JWT fit into this whole thing? Remember in our scenario, the Resource Provider (one more time, that’s the NodeJS RESTful application) is deployed on Heroku. AAD which is the Authorization Provider is running on Microsoft Azure cloud somewhere. Already you can see the decoupling. The only small and imaginary link between the Authorization Provider and the Resource Provider is the JWT. So how does JWT link them?

The Authorization Provider (AAD in our scenario) generates and issues the token (JWT). AAD signs the JWT with its private key. Hence, sometime it can be referred to as a Token Issuer.

The Resource Provider must be able to validate the token (JWT) issued by the Authorization Provider. Resource Provider validates with a public key.

Step 1: Write the Resource Provider

var express = require(‘express’),
app = express(),
fs = require(‘fs’);
app.get(‘/books’, function(req, res) {
fs.readFile(__dirname + ‘/’ + ‘_data.json’, ‘utf8’, function(err, data) {
res.status(200).send(data)
});
})
var server = app.listen(8080)
console.log(‘Server listening on port 8080’)

We keep the data in the file called data.json file like so:

[
{
“author”: “Mark Twain”,
“text”: “Adventures of Huckleberry Finn”
},
{
“author”: “John Steinbeck”,
“text”: “Of Mice and Men”
},
{
“author”: “Harper Lee”,
“text”: “To Kill a Mockingbird”
}
]

Of course, the goal here is not to show how to write a NodeJS RESTful application. Rather, the goal is to show how we will secure the /books resource. We will see this shortly.

Step 1: Configure Azure AD

  • Logon to https://manage.windowsazure.com/
  • Refer to Figure 1, click on the icon shown in red box labelled 1, then the Default Directory link shown in box 2. If not selected, click on the Applications link in the horizontal tab (not shown). Then click on the Add button in box 3. You will get a prompt asking “What do you want to do?” as shown in Figure 1. Pick the first choice “Add an application my organization is developing” as shown in box 4.
Image for post
Image for post
Figure 1
  • On the next screen, Figure 2, name it SampleWebService and pick Web Application And/Or WebAPI.
Image for post
Image for post
Figure 2
Image for post
Image for post
Figure 3
  • Click the check mark button and you should now see something like in Figure 4
Image for post
Image for post
Figure 4
  • Scroll down and click on Add application. Unless the UI changes, that’s the big button in green. You can see it Figure 4.5 and Figure 5.
  • On a new page that pops up, click on the Plus sign on the same line where Microsoft Graph is, and then click on the Complete Check sign at the bottom left of the page.
  • Microsoft Graph will now shows up as in Figure 4.5. Now, set the Permissions to Windows Azure Active Directory and Microsoft Graph so they will all have Read and Write permissions to Directory data as follow:
Image for post
Image for post
Figure 4.5

You should now see:

Image for post
Image for post
Figure 5
  • So we just created a Web Application/Web API in AAD called SampleWebService. This is how AAD knows about our NodeJS REST application, i.e. our Resource Provider. In other words, this is how our Resource Provider is represented in AAD. Next, we have to do something similar to represent our Client Apps in AAD.
  • Do the same as we did what led to Figure 2. Except this time, we pick Native Client Application and name the application SampleClient.
  • In the next screen, give Redirect URI this value http://sampleclient.azure-mobile.net
  • Navigate to SampleClient->Configure, click Add Application
  • Filter by App Apps and pick SampleWebService.
  • Give Access SampleWebService as shown in Figure 6.
Image for post
Image for post
Figure 6
  • Click on the Save button to save everything.

Test everything that we have configured so far

  • We created a so-called Web Application/Web API in AAD.
  • We created a so-called Native Application in AAD.

Each application that we create here in AAD has a unique App ID generated for it. AAD is responsible for creating these unique App IDs. When our Resource Provider and Client Apps need to “talk” to AAD, they will send these App IDs somehow. This is how AAD can identify who is sending it the requests.

I believe we just finished the “least favorite” part which is the configuration on Azure AD. We can take a moment now to make sure that what we have configured are in good shape. The configuration is also the most important that if we didn’t get it right, there’s no amount of code that we could write to make it work. So let’s take a moment. I prefer to use Postman but you can use Fidler or other tools.

To test we must have a user. Later on, we will write code to create users programmatically when users signup. But for now, we will create a user for testing purpose manually.

Make sure you’re still in the AD tab (vertical tabs on the side) in the portal. Navigate around until you find a Users tab (horizontal tabs on the top). Other tabs at the same level with Users are Groups, Applications, Domains, Directory Integration, Configure, Reports and Licenses.

Now try to create a user. The Type of User you should select is New user in your organization. The remaining are answering some very basic questions. Note the email and the password of this new user. To have this user available for testing, we must change the password of this user. Do so by pointing the browser to https://login.windows.net

Proceed by changing and confirming the password.

Now to test if the new user can login, i.e. can be authenticated by Azure AD, we will make the POST request from Postman

Image for post
Image for post
Figure 7

From Figure 7, part of the URL end point includes the tenant in your Azure AD. To get your tenant, click on Default Directory->Domains (shown in Figure 8 and the tenant is underlined).

Image for post
Image for post
Figure 8 — The domain which is underlined is part of the POST request URL end point in Figure 7

To get the value for the resource, select SampleWebService->Configure then copy the App Id URL as shown in Figure 9.

Image for post
Image for post
Figure 9 — App ID URL is the value for the resource param of the POST request in Figure 7

For the client_id params, select SampleClient->Configure then take the Client ID, as shown in Figure 10.

Image for post
Image for post
Figure 10 — Client ID here is the client_id in the body of the POST request in Figure 7

For 4 and 5, remember the user we created manually earlier. Use its username and password.

Send the POST request, and the response coming back should be something like in Figure 7. If you see that, we have configured ADD correctly.

Write NodeJS REST API Provider

The access_token will be used by the client apps (that we will write later) to access the protected resources provided by the NodeJS REST application. So let’s go ahead and write the secured NodeJS REST application (the unsecured version was introduced earlier).

Make a new working directory. First let’s do

npm init

then install the following 3 npm packages:

npm install jsonwebtoken --save
npm install azure-ad-jwt --save
npm install azure-graphapi --save

Now write your server.js as follow:

The endpoint /books is now protected (or secured as I have used these 2 terms interchangeably).

If you point your browser to this endpoint or use Postman now, you will get a 401 (Unauthorized).

To get a 200 OK status with the data, in the GET request header, add an Authorization attribute and the value of the Authorization attribute is:

bearer access_token

where access_token is the access_token that was returned as shown in Figure 7.

Figure 11 shows how to send an authenticated request that we just talked about

Image for post
Image for post
Figure 11

If you look at the code from line 8 through line 11, that involves pulling out the access_token (which is in the form of a JWT). The heavy lifting is done by the package azure-ad-jwt, which you can read from its site and also a link in the Reference section at the end of this post.

So with the access_token, we can access the protected Resource Provider all day long? Not quite, refer back to Figure 7, you’ll see the access_token expires in 3599 seconds. After the access_token expires, sending the access_token like we did in Figure 11 won’t do any good. So what to do then?

One way is to keep the username/password around in the Client Apps after the user has entered. This is a bad idea. Never store the username/password in the mobile apps or worse in the local storage if we’re building a web application.

Another way is to NOT to store the username/password, and when the access_token expires, we prompt the user to enter again. That means we prompt every 1 hour. This will also be a big inconvenience for the user.

Fortunately, there’s a third way. I mentioned briefly about the refresh_token. We can simply exchange the refresh_token for another pair of access_token/refresh_token. This is straightforward which you can see in Figure 12.

Image for post
Image for post
Figure 12

Final Points

  • Configure a Web Application/Web API in AAD. Configure a Native Application in AAD. In AAD terminology, we “create” these applications.
  • Manually create a user in AAD and change its initial temporary password.
  • Write a secured NodeJS REST application that is a Resource Provider. This application is decoupled from AAD. It only knows how to validate an AAD-issued JWT. It does so with the help of the library azure-ad-jwt.
  • Make a POST request to the URL end point https://login.windows.net/yourtenant.onmicrosoft.com/oauth2/token to get an access_token in the response. We also get a refresh_token. There are several query params, but notice that grant_type query param here is password.
  • Make an authenticated REST call to the protected REST API end point. Put the above access token in the bearer scheme which goes in the Authorization attribute of the request.
  • When the token expires, make the same POST request to the URL end point https://login.windows.net/yourtenant.onmicrosoft.com/oauth2/token, but the grant_type in the query param is refresh_token.

Why is this a good approach?

What’s ahead? I will show:

  • How to programmatically create a user in AAD. This simulates the scenario when users signs up.
  • Write an iOS client in Swift, a Xamarin Form client, and maybe more.

So stay tuned, follow and like.

References

Written by

Driven by passion and patience. Read my shorter posts https://dev.to/codeprototype (possibly duplicated from here but not always)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store