Angular 2 – Building the OAuth2 server using nodeJS

Hi Friends,

Hope you are all well. This is a response to many of our friends asking me to do a post on Oauth2 authorization method in our nodeJS backend. I am sorry since this took a really long time, but here we go.

First of all this post is heavily inspired by the blog post from Scott K Smith. His is the most read post on Oauth 2 and NodeJs which he wrote a couple of years back.

A screencast of this post:

 

The complete code for this repo can be found here.

We will be making use of the JWT based authentication system which we have already written.

Please grab a copy of that repo from here.

 

Now open it up in your favourite code editor and let’s do some reorganising.

Create a new file in the methods directory as auth.js and copy all the code from config/passport.js into it. Then delete the passport.js file.

Open up your server.js file and remove the below line.

Okay. Now for a moment forget about all the code and look at the flow of OAuth 2.0

Let’s consider Twitter, Google or any other company using OAuth; the following steps will be common.

Step 1:

You will register your app with their platform (something like developer.twitter.com) and they will provide you with an APP_ID and a secret.

Step 2:

Then you will make a call to their platform from your App (Usually to an URL like /companyname/authorize) along with your App_Id and secret. You will get a bearer token in return.

Step 3:

You will then use this bearer token to make a call to a different URL which would then return an access token. If you receive the access token then you are authorized.

Step 4:

Then you could use this access token to make authorized requests to the API’s without using your username or password anywhere.

So, we’ll need to design our server in such a way that it includes all the above 4 steps.

Okay first of all let’s open up our model directory and create a file called book.js. Open this and add the below code.

Also open up methods/actions.js and add the below two functions.

Dont forget to add the require() for Book model

We have just created provisions using which a user can add a book or view the list of added books.

The code might look a lot similar if you had read Scottksmith’s blog. I used most of his code with a lot of changes too.

Now let’s get into the steps.

First let’s create a model for the client

Create a new file called client.js inside model and add the below code.

Okay now that we have model let’s write functions for adding a client and getting the clients.

Open up methods and create a new file called client.js and add the below code.

Okay. Now before the user tries to add a client, we must first check whether he is authenticated right ?

So let us assume here that the user sends a POST request to create a new client and includes his JWT in that request header. (JWT as in the one which was created when he logged in).

Then the jwt is checked up using the strategy we wrote in auth.js file and then if it’s successful, i.e., the user is present a client is added and a client_id and secret is sent in response.

Now open up auth.js and modify it slightly so that it looks like below.

Now we could simply call up auth.isAuthenticated anywhere to check whether the user is authenticated or not. (Provided he sends a request containing the jwt token).

Now open up routes.js inside the routes folder and add the below lines of code.

this is for adding the clients.

Okay. Now after the client is added. The app_id and the secret are passed on to the user with which he makes the next request right..?

So, we need to handle that now.

Install oathu2orize npm module using the below command.

Install passport-http-jwt-bearer too using the below command.

Let’s create models which we would be using for the code and the token.

Open up model folder and create a new file called token.js

Create another file called code.js and add the below code to it.

Now create a new file called oauth2.js in methods folder and add the below code into it.

Let’s look at this code in a minute. For now we’ll progress on and finish the code so that we could understand the flow better.

Install passport-http using the below command.

 

Open up auth.js and add the below code so that it looks like below.

We have added two more strategies here. But as I said before let’s continue and finish the flow.

Open up routes.js and add new routes. Now routes.js should look like this.

Now for oauth2orize module we need sessions., so we will install express-session using the below command.

Now open up  server.js and add the below code so as to include sessions in our app.

Note that we have also set the view engine to ejs.

Okay. That’s it. Now, remember our steps. Let us say you have added a client and now you want to access the REST Apis. So you send a get request to /oauth/authorize along with the client_ID & redirect_uri (This will usually be added along while you register the client).

So that route invokes oauth2.authorization. Look up oauth2.authroization in your oauth2.js file. You could see that it simply references the Client in the client db using the client_id and then returns a client and tries to call the redirect URL.

Okay; usually apps would ask you permission before allowing the registered client to access Apis right?

For eg., this is what twitter would show when you make REST calls.

oauth2]

we need to create a similar interface for our apps too right ?

Once again we will be using code from Scottksmith’s blog.

We will be using ejs template engine for our view. Create a folder called views and create a new file inside it called dialog.ejs and then add the below code in it.

If you notice we are merely ask the user for a confirmation and then a POST request to the ‘/oauth2/authorize’ Url is made.

Now the POST request invokes the oauth2.decision in oauth2.js file.

Now this will trigger the server.decision(). The server.decision() method triggers the server.grant code whose looks as shown below.

If you notice we simply generate a code and then saves it. It also returns the value of the code to the calling app.

Okay. So far so good. Let’s remember the next steps of our app. This code could be exchanged for an access token right.

This is where the ‘/oauth2/token’ endpoint comes in. Send a post request to this endpoint along with your Client ID and secret in the header(base64 encoded) and also send the code which you received from the previous step.

Our basic strategy in passport will check if the client is found using the client_Id. Then the oauth.token function will call the server.exchange function whose code looks like below.

If you notice you will see that it checks up the code which we saved previously and then generates a new token. This token is saved and then returned.

Note that the token is encoded first into a json web token using our secret.

This is essential since we will be making use of this token to do all our authorized requests. If you look at the JwtBearerStrategy in auth.js

You can see from the above code that we are first decoding the token using our secret again and then searching for this token using the id and then if it’s present then the token is considered to be valid and the user is authorized to use the resource.

Important things to notice:

  1. We will never be using our username password anywhere after logging in.
  2. Multiple request,responses take place and thats where the serialization and deserialization in oauth2.js file are used.

 

If you feel confused kindly watch my video screen-cast. I believe I have explained it a bit more clearly there. Or read this article once again. You could ask me anytime if you are stuck (use the comments section).

Alternatively you could grab a copy of this repo and try it out using Postman.

In the next part we will be building an Angular 2 app to consume these REST Apis. Since we will actually be using the code we wrote here, your doubts would get cleared and you would get a better understanding of the flow.

If you found this helpful kindly share it with someone else and help them too.

Thanks for reading guys. Peace.. :)

Liked it? Take a second to support admin on Patreon!