How to secure your HTTP API endpoints using Facebook as OAuth provider

Standard

Heads up!

The blog has moved!
If you are interested in reading new posts, the new URL to bookmark is http://blog.valeriogheri.com/

 

This post is the natural follow-up of my post “How to build and test your Rest API with Node.js, Express and Mocha”.
Here I’ll show you a possible solution to the problem of authenticating your API users via Facebook, accessing some user’s basic info like name, profile pic and email and using the given Facebook access token to secure all your API endpoints.

Solution:

This is quite a common scenario nowadays yet I couldn’t find many useful source of information. So I went ahead and asked a question on StackOverflow (http://stackoverflow.com/questions/15602667/possible-approach-to-secure-a-rest-api-endpoints-using-facebook-oauth). The solution described below is heavily inspired by the answer given by user Tommy Crush, so thanks Tommy!

The logical steps are:

  1. Login via Facebook on your app (either mobile or web) and obtain the Facebook Access Token

  2. Pass the Facebook Access Token to the server (over SSL for the android app, and for the web app just have it redirect to an API endpoint after FB login)

  3. Check the given Facebook Access Token to make sure it is valid by making a graph call to the /me endpoint. Parse the response to get user id and email and cross-reference this with existing users to see if it’s a new or old one.

  4. Now create a random token, store it and associate it to the user id and give the API token back to the requesting app. If you need Facebook for anything other than login, store it too in your DB and associate it with the new api_access_token and your user_id.

  5. For every call hereafter, send the api_access_token to authenticate it. If you need the fb_access_token for getting more info, say retrieveing the list of your user’s friends, you can do so by retrieving it from the DB.

Code:

The code shown below  is taken from my current project ShopWithMe available on GitHub  (https://github.com/vgheri/ShopWithMe) and uses a Node.js + Express.js + MongoDB with mongoose technology stack.

I’ll go into details starting of points 3 and 5. Points 1, 2 and 4 should not be a issue.

Step 3: Verify facebook access token

To verify if the given token is valid we need to make a call to the /me endpoint of the Facebook Graph API located at the URL https://graph.facebook.com/me?access_token=$fb_access_token
The result, if token is valid, is a JSON blob containing the user’s information accessible using this token.
This blob should, at its minimum, look like the following:

{
  "id": "xxxxxx",
  "name": "XXX XXX",
  "first_name": "XXX",
  "last_name": "XXX",
  "link": "https://www.facebook.com/XXX",
  "username": "xxxxxx",
  "gender": "xxx",
  "email": "xxx",
  "timezone": 2,
  "locale": "en_US",
  "verified": true,
  "updated_time": "2013-08-14T09:16:58+0000"
}

Otherwise should we have an error response, that’s the JSON blob we’ll get back:

{
  "error": {
    "message": "XXX",
    "type": "OAuthException",
    "code": XXX,
    "error_subcode": XXX
   }
}

As a hint, if you want to try this on the browser, just go to https://developers.facebook.com/tools/explorer/?method=GET&path=me being logged in with Facebook on your browser. Obtain the Facebook Access Token and then point your browser to the URL https://graph.facebook.com/me?access_token=$fb_access_token , where $fb_access_token is the token you just obtained. You should see a JSON object containing your info if all went well (why shouldn’t it? J)

Point 5:
Point 5 is about securing your API endpoints, making sure that only authenticated users can access the data and authorize the request.
Express.js has a nice and easy way to allow a developer to play with the request pipeline, all that is needed is adding a function in the route declaration.
Let’s see how:
In the file where I defined my routes, I just need to update the routes I want to secure, simply modifying them like this:

BEFORE:
app.get(‘/api/profiles/:userId’, handlers.account.getAccount);

AFTER:
app.get(‘/api/profiles/:userId’, authorisationPolicy, handlers.account.getAccount);

As it should be clear, I just added a function called authorisationPolicy to the route declaration that inside the pipeline is processed ahead of the handlers.account.getAccount function .
Let’s see into detail this authorisationPolicy function:

This function executes its authentication policy and if everything is fine, it calls the Express.js next() function, which takes care of executing the next stage in the pipeline.
If otherwise the request should not be authorized, we can send back an error response.

Conclusion

In conclusion what we have seen is a simple yet effective way to integrate Facebook login into your HTTP API and to secure your endpoints.
The key here is to use the Facebook token to identify your users and then to issue your own API tokens to secure your endpoints.

Advertisements

How to build and test your Rest API with Node.js, Express and Mocha

Standard

Heads up!

The blog has moved!
If you are interested in reading new posts, the new URL to bookmark is http://blog.valeriogheri.com/

 

If you need to build an API, you want it done quickly and simply and you love JavaScript, then this article is for you!
I’m going to show a simple, quick and effective way to build and unit test your API and your routes, using Node.js, Express and a few amazing test libraries: Mocha, SuperTest and should.js that integrate very well together in a natural fashion.
The API style is Rest, that is it leverages URLs and HTTP verbs, but I won’t go much into details in this tutorial.
If you ever used technologies such as WCF, you will be amazed at how much quicker it is to build your API with Node, there’s virtually no machinery to put in place, no service references to update, no WSDL… it’s pretty much just logic to implement!
Of course when you want to design your API around a Rest concept, it is very important to think about the access paths to your resources, they NEED to make sense and to be well structured, otherwise you just end up walking down the good old RPC path.
For a nice intro to this concept, see http://www.slideshare.net/domenicdenicola/creating-truly-res-tful-apis
By the way, in this tutorial I won’t cover advanced topics such as securing the API through HMAC or OAuth solutions.

From words to code:

A nice and free dev environment where to start coding is cloud9 (https://c9.io), as  it offers everything you need and maybe more: a text editor with syntax highlighting, a Node.js environment, a debugger (!), a shell, cloud storage and it connects to your GitHub repository… because you have a GitHub repository, don’t you? We don’t need more than that to write our first API, so let’s start!

Ok we want to write a HTTP API, so we obviously want our API to be accessible via some sort of webserver, but as you may already know, Node.js doesn’t come with its own webserver.
Instead it comes with some facilities built-in; on top of these facilities lies Express.js, the web server of choice for this tutorial. Express.js (http://expressjs.com/) describes itself as a web application framework for node, and I think you should use Express too, as it is a solid and well tested piece of software, easy to setup and test.

After reading some tutorials around, I came up with a structure of 4 short files  that setup and run the API:

  1. config.js exports an object that contains all configuration keys and values, pretty much like web.config in an Asp.Net web app. Following this line we can think about having a config-debug.js  and a config-release.js. We’ll see later why.

  2. routes.js exports a setup function that takes care of declaring the routes and the handlers that will manage each request.

  3. server.js where we configure Express and we export a start function that takes care of setting up the routes and starting the web server

  4. index.js is the entry point of our API. It uses pretty much everything we have defined so far to start the logger (my logger of choice is winston), to connect to a database, if present, and to finally start the Express server.

config.js

routes.js


As you can see, setup expects two parameters: app is the Express app and handlers is an object that maps to a set of functions that handles user requests. Each of these functions accepts as parameters the request and response objects: e.g.

function handleCreateAccountRequest(req, res) { … }

server.js

The first part is just some standard Express setup + Express logging.
Now we can see clearly what the parameters for routes.setup are: app is just the Express instance and handlers contains two objects that point to the different handlers that will be able to handle API requests.
Finally, after declaring and exporting the start function, this module exports the Express instance, which will be used in the tests.

index.js

As already said, index.js is the entry point, that means our API will be executed by running the command

$ node index.js

We can easily configure the API logger using winston and the configuration file, we connect in this case to MongoDB using mongoose, a fantastic tool, and then we start the server using the freshly exported function.
That’s it, you don’t need anything else to setup your API along with a solid logger and a database connection.

Ok I have an API but… how do I test it?

The test framework of choice for this tutorial is Mocha (http://visionmedia.github.io/mocha/) along with Supertest for HTTP assertions (https://github.com/visionmedia/supertest) and Should.js for BDD style tests (https://github.com/visionmedia/should.js). Mocha is a great choice because it makes async test natural and fluent.

The purpose here is to unit test our routes  (integration tests) and to build the tests so that we will be able to read our test and the results as if they were plain English sentences!
Let’s create a folder named “test” where we will place our test files and our mocha.opts configuration file where we can specify the output style for our tests.
Finally we can create our unit tests for the routes in a file called “test/routes.js”.

The structure of a test with Mocha is simple and verbose:

So if you try and read the test, it would come out something like:
Describe Routing, describe Account, it should return error trying to save duplicate username, it should correctly update an existing account, and so on.
To add more test, simply add more describe or it functions, and that’s it!

To execute the tests, start your api with

$ node index.js

and then in another shell run

$ mocha

as by default mocha will run everything in /test off of your main project.

If you want to run your test by typing

$ npm test

then all you have to do is to create a makefile and can even be as follows:

then add the following lines to your package.json file:

“scripts”: {
“test”: “make test”
}

and that’s the result (note that in the screenshot I have more tests as it’s taken from an actual project of mine)

Mocha test output with BDD style

Mocha test output with BDD style

That’s it, pretty easy, isn’t it?