undefined

If you need to implement security into your API, and you only have server to server or app to server communication, then a 2-legged oauth security implementation is a good choice. In a 2-legged scenario, you only secure that the consumer of your API is who it claims to be. This is done by creating a hash of all the data that you send to the API, together with a secret, and sending the hash together with everything to the server. On the server side, your API does the same, and since the secret is never sent between the two parts, but just used to compute the hash, it knows that the consumer is who it is supposed to be.

Quick walkthrough

There are lots of detailed explanations on how this works, but basically its something like this:

  1. The server and the consumer have both a public and a secret that only they know.
  2. When the consumer wants to send something to the server, it takes the data it wants to send and computes a hash with the content and the secret.
  3. The content together with the hash, a timestamp and the key is sent to the server as a request.
  4. When the server receives it, it does the same calculation of a hash. If the hash the server receives, and the hash calculated on the server, are the same, then we know that everything is ok
  5. Since the secret is never sent with the request, the server knows that the only one that could create that specific hash is the the one that has the secret, thereby knowing that the consumer is the correct consumer.

Now, since the secret is what makes this method secure, it can never be shared to others. Thats why a 2-legged oauth is good for server to server, but not for browser to server communication, since the browser cant protect the secret.

Implementing it in node - as easy as it gets

By using the passport module, we can create an 2-legged oauth implementation with just a few rows of code. Naturally, the example below is simplified. In a real application you would need a database with a list of key/secret pairs, provably together with some user or app info. In this example, we'll just create a small static list just to show how it can be used.

First of, we install what we need for this example:

npm install express passport passport-http-2legged-oauth

Creating an app list

Lets create a list for all the apps and save it as apps-model.js:

var appList = [
    {
        key: "abcdefg", // this is the public key for an app
        secret: "12580ierouybjcvbmsdhfku2367i", // this should be long, longer than my example,
        name: "One cool app"
        // We could also have information in this list about what data
        // the user has access to, the last time it was used, how many times
        // it has been used etc etc etc. This is basically the user info
    }, {
        key: "asecondkey",
        secret: "xxccvvbbnnmmaassddffgghhjjkkll",
        name: "Another app"
    }
];

// We create a function that finds the app by checking for the key.
// In a real world example, this would provably 
// check against a database, and would provably be async
exports.find = function(key) {
    for (var i = 0, ii = appList.length; i < ii; i++) {
        if (appList[i].key == key) {
            return JSON.parse(JSON.stringify(appList[i]));
        }
    }
}

The server

Now we have a lis of users. The next step is to create the server. We use express for the endpoints and passport as the security framework. We also load passport-http-2legged-oauth's strategy, ie our 2-legged implementation. We also create some endpoints to show how we secure them.

Lets create a file called server.js:

var express = require('express'); 
var app = express();
var passport = require('passport');
var twoLeggedStrategy = require('passport-http-2legged-oauth').Strategy;

// Load our model with all apps
var appsModel = require('./apps-model'); 

// This is standard passport
app.use(passport.initialize());

// And here we start the http server and listen to port 1337
app.listen(1337);

// We add a route that is open, i.e. public
app.get("/", function(req, res) {
    res.setHeader("content-type", "text/html");
    res.send("Hi. Try <a href='/private'>/private</a> for a private endpoint.");
});

// And we add a secure route. Add the security and that we 
// aren't using any sessions (no point in 2-legged), 
// since each request will be signed
// Passing 'oauth' to pass.port.authenticate is what marks that 
// we use endpoint with the security implementation in passport-http-2legged-oauth
app.get("/private", [passport.authenticate('oauth', {session: false}), function(req, res) {

    // send something back that is only access by a signed request of a known app
    res.send({secret: true});

}]);

So what we have done so far is:

  1. Start an express server
  2. Initiate passport
  3. Create two end points, one public and one private
  4. Create a list of apps and load it

Implementing the security check

The code above sets the base for our example. The only part that is left is actually implementing how this specific solution will check for it's apps and make sure a an app is found in our list. In other words, this is what we need:

  • We need a function that will take one key (the one that comes from a request) and checks if it finds an app with that key. This is comparable with checking if a user exists in a database.
  • We also need a function that checks if the request is fresh enough, i.e. we don't want to accept request that are too old.
// A function that check if the key is valid and gets the secret
function checkAppKey(key, done) {
    var app = appsModel.find(key);
    if (!app) { 
        // We couldn't find an app, so lets call the next callback 
        // with the signature that passport expects
        // when we don't find a user. In a real world example, 
        // we should also check if an error occurs when getting
        // the app, but since this examples app model is so simple, 
        // we don't need it. Thats why we just send null as the first argument.
        return done(null, {error: 'app not found'}); 
    }

    // Now we know that we found an app, so call the passport
    // callback with the app and the secret
    // which passport-http-2legged-oauth will use to check if 
    // the incoming request is reliable.
    return done(null, app, app.secret);

}

// Function to check if the timestamp is ok (and nonce, but we don't check nonce in this example)
function checkTimestampAndNonce(timestamp, nonce, app, req, done) {

    var timeDelta = Math.round((new Date()).getTime() / 1000) - timestamp;

    // Here we check if the request is too old.. If its too old, 
    // return false which means that we don't accept the request
    if (timeDelta >= 10) {
        done(null, false);
    }
    else {
        // This is when everything is ok
        done(null, true);
    }

}

Last, but a very important step, we register our two security functions so that passport knows what to look for.

passport.use(new twoLeggedStrategy(checkAppKey, checkTimestampAndNonce));

Thats it! Now we have a finished server with 2-legged oauth 1.0a security. These are the last three things we did:

  • Create a function that knows how to find an app from a key, and make sure we react if we don't find and app
  • Create a function that checks if the request is fresh enough
  • Register the two functions so passport knows what to do

Now that the server is secure, you can't access it unless you use a client that uses the key and secret (except the public endpoint we created). So lets start the server and begin to create a simple client.

node server.js

Creating a simple client

Now that the server is running, we create a client. But first we need to install an oauth client (lets use node-oauth)

npm install oauth

Now we create the client and save it as client.js


var oauth = require("oauth");

// Here we set the key and secret we want to use for this app
var key = "abcdefg";
var secret = "12580ierouybjcvbmsdhfku2367i";

// Create the client we use to request everything. The first two parameters aren't needed since we use it for 2-legged
// and not 3-legged
var request = new oauth.OAuth(null, null, key, secret, '1.0', null, 'HMAC-SHA1');

// And now, finally, we can access our endpoint
request.get("http://localhost:1337/private", null, null, function(err, data, res) {
    if (err) {
        console.error("Err", err);
    } else {
        console.log("Success", data);
    }
});

Now run the client:

node client.js

... and it should print out "Success..." and the data from the endpoint.

Thats it

As you can see, you don't need much code to implement this. Even if this is a little simplified, its quite near a real world scenario.

All code can be downloaded here: downloaded here.

Last words

Remember that a 2-legged solution is great when you have a consumer that can keep a secret. It will guarantee that the consumer is the real consumer, and with all libraries for auth, you can consume it from almost any language.

The code for passport-http-2legged-oauth can be found here: https://github.com/camme/passport-http-2legged-oauth