Update 5/11/2016: Developing in Node.js? Try out nJwt, the cleanest JSON Web Token (JWT) library for Node.js developers, built and maintained by Stormpath.

Building APIs is a craft; you have you have to balance the integrity of your data model with with the convenience needs of your API consumers. As you build an API, you will come across these questions:

How do I model my data?

How do I authenticate users?

How do I create and distribute credentials for my API?

How do I do access control for the resources in my API?

How should I write the client libraries for my API?

How will I secure access to my API?

In this article I’ll focus on the concerns of authentication and access control, specifically within the context of Restify – a Node.js Framework for building APIs. I will walk you through the process of building an API with the Restify framework and how you can secure it with Stormpath’s API Authentication features.

We’ll be using the OAuth2 Client Credentials workflow as an authentication strategy and JWTs for the format of the tokens.



I’ll touch on client libraries and the resource design. That section is heavily influenced by how we have designed our own API and I encourage you to read our principles on Designing REST JSON APIs

and Node API Clients

Why Restify?

Restify is an HTTP framework for Node.js that is focused on building API applications. It differs from Express (the other Node.js web framework) in it’s focus is on APIs. Express gives you a lot of things you need for web applications, like templating engine and component-like “middleware” design. Because Restify is focused on APIs it does not provide those things. Instead it provides things like DTrace support and request throttling – very important tools for API services.

What is Stormpath?

Stormpath is an API service that allows developers to create, edit, and securely store

user accounts and user account data, and connect them with one or multiple applications. Our API enables you to:

Authenticate and authorize your users

Store data about your users

Perform password and social based login

Send password reset messages

Secure and authenticate users to your API – (the focus of this article)

And much more! Check out our Product Documentation

In short: we make user account management a lot easier, more secure, and more

scalable than what you’re probably used to. Our sample application will use

Stormpath to provision API keys for the users of our API.

Ready to get started? Register for a free developer account at https://api.stormpath.com/register

Why OAuth2 and JWT?

The current de-facto practice for API Authentication is to provide an API Key/Secret combination to the consumer of your API and have them submit this as the Authorization header on every request, which looks like this:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== 1 2 Authorization : Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ ==

The value after Basic is a Base64 encoded version of they key and secret in the format API_KEY_ID:API_KEY_SECRET. This will be sent on every request. Assuming you use HTTPS, this is a secure way to authenticate users.

In our demo application we will take this a step further and use OAuth2, specifically the client-credentials workflow. In this workflow the user supplies the Basic Auth once and then receives a token that contains “claims” which can be used for authentication (and access control!) on subsequent requests. The token is always validated by your server, and because it already contains the claims, it is stateless.

Here is an overview of what the flow looks like:

The stateless, portable nature of the token makes this strategy superior to Basic Auth. It also helps to future-proof your application for when your customers ask for it.

At Stormpath, we use JWT as the token format because we believe it’s a great way to structure the internal data of the token. If you’re looking to build a Single-Sign-On (SSO) architecture you will find JWT very friendly for that use case. Also: it’s well known as the standard for Oauth tokens.

For more see Claims Based Identity and JSON Web Token (JWT)

Our Sample Application – The Things API

For our demo application we’re going to build the Things API.

We have a collection of things which will be available at /things . We want to return a collection of all things when someone makes a GET request to that URL. If someone posts to it we will create a new Thing in the Things collection and we will assign it an ID.

All individual thing resources will be available as /thing/:id and we will allow deletion of things.

All users (including anonymous users) must be able to read the things collection, but only authenticated users will be allowed to post new things. Only trusted users will be allowed to delete things. Trusted users will be in a special group (we will use Stormpath to manage the user group state).

We’ll be creating three separate node modules: a server, a client library, and an example app that uses the client library. Our code structure will look like this:

|--things-api-server/ | |--server.js | |--things-db.js | |--package.json |--things-api/ | |--index.js | |--register.js | |--package.json |--developer-app/ | |--app.js | |--package.json 1 2 3 4 5 6 7 8 9 10 11 12 | -- things - api - server / | | -- server . js | | -- things - db . js | | -- package . json | -- things - api / | | -- index . js | | -- register . js | | -- package . json | -- developer - app / | | -- app . js | | -- package . json

As we work through this demo, we will be context switching between these different folders and files. If you get lost or aren’t sure where to paste something please see

the example files in the git repo to get a preview of what the final code will look like

HTTPS – Make Sure You Use It

You MUST use HTTPS in production!

In this demo we will work on our local machine and will not using HTTPS – but you MUST use HTTPS in production. Without it, all API authentication mechanisms are compromised.

You have been warned.

Server Prep – Create the Server Module

If you don’t already have Node.js on your system, head over and install it on your computer. In our examples I will be using a Mac, all commands you see should be entered in your Terminal (without the $ in front – that’s a symbol to let you know that these are

terminal commands).

First, create a folder for this module and change into that directory:

mkdir things-api-server cd things-api-server 1 2 3 mkdir things - api - server cd things - api - server

Now that we are in the folder we want to create a package.json file for this module. This file is used by Node.js to keep track of the libraries (aka modules) your module depends on. To create the file:

npm init 1 2 npm init

You will be asked a series of questions, for most of them you can just press enter to allow the default value to be used. I decided to call my main file server.js , I set my own description and set the license to MIT – everything else I left as default.

Now install the required packages:

npm install --save restify stormpath-restify uuid underscore 1 2 npm install -- save restify stormpath - restify uuid underscore

The save option will add this module to your dependencies in package.json. Here is what each module does:

Restify is the HTTP framework that we’ll use to build the server

Stormpath-restify is a Stormpath helper library that provides filters (“middleware”) which handle the authentication bits

Uuid is a library for generating random, unique strings

Underscore is a utility library for working with objects and arrays

Note: Restify parlance uses filter in lieu of middleware. Both are valid, but for consistency we will use filter here.

Coding Time – Build the Server Code (server.js)

It’s time to create the actual server – the Node.js process that serves API requests. You can do that via a text editor like Atom or Sublime, or via the terminal:

touch server.js 1 2 touch server . js

Now open that file and paste in this boilerplate to get Restify up and running:

var restify = require('restify'); var host = process.env.HOST || '127.0.0.1'; var port = process.env.PORT || '8080'; var server = restify.createServer({ name: 'Things API Server' }); server.use(restify.queryParser()); server.use(restify.bodyParser()); server.use(function logger(req,res,next) { console.log(new Date(),req.method,req.url); next(); }); server.on('uncaughtException',function(request, response, route, error){ console.error(error.stack); response.send(error); }); server.listen(port,host, function() { console.log('%s listening at %s', server.name, server.url); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var restify = require ( 'restify' ) ; var host = process . env . HOST | | '127.0.0.1' ; var port = process . env . PORT | | '8080' ; var server = restify . createServer ( { name : 'Things API Server' } ) ; server . use ( restify . queryParser ( ) ) ; server . use ( restify . bodyParser ( ) ) ; server . use ( function logger ( req , res , next ) { console . log ( new Date ( ) , req . method , req . url ) ; next ( ) ; } ) ; server . on ( 'uncaughtException' , function ( request , response , route , error ) { console . error ( error . stack ) ; response . send ( error ) ; } ) ; server . listen ( port , host , function ( ) { console . log ( '%s listening at %s' , server . name , server . url ) ; } ) ;

That’s the bare-bones you need to get the server running! This does the following:

Require the Restify module

Setup a port and host to bind to, with 127.0.0.1:8080 as the default

Tell Restify to use the Body Parser, used for reading POST data

Tell Restify to use the Query Parser, used for reading URL query params

Registers an anonymous filter, which just prints out the URLs

being requested

being requested Implements an uncaught exception handler, which tells us about

any internal server errors

any internal server errors Starts the server up by binding to the host and port

You can take a sneak peak at your server by running it like so:

node server.js 1 2 node server . js

When the server starts, you should see this message in your terminal:

Things API Server listening at http://127.0.0.1:8080

At this point you can make a request to the server. We’ll use Curl for the example. Open another terminal (so that you have two open) and run this command:

curl http://127.0.0.1:8080/ 1 2 curl http : //127.0.0.1:8080/

Because we haven’t created any routes in the server yet, you will get a “Resource Not Found” message:

{"code":"ResourceNotFound","message":"/ does not exist"}

You can inspect the details of this message by specifying verbosity with Curl, like this:

curl -v http://127.0.0.1:8080 * About to connect() to 127.0.0.1 port 8080 (#0) * Trying 127.0.0.1... * Adding handle: conn: 0x7fb32c004000 * Adding handle: send: 0 * Adding handle: recv: 0 * Curl_addHandleToPipeline: length: 1 * - Conn 0 (0x7fb32c004000) send_pipe: 1, recv_pipe: 0 * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.30.0 > Host: 127.0.0.1:8080 > Accept: */* > < HTTP/1.1 404 Not Found < Content-Type: application/json < Content-Length: 56 < Date: Mon, 03 Nov 2014 04:58:27 GMT < Connection: keep-alive < * Connection #0 to host 127.0.0.1 left intact {"code":"ResourceNotFound","message":"/ does not exist"} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 curl - v http : //127.0.0.1:8080 * About to connect ( ) to 127.0.0.1 port 8080 ( #0) * Trying 127.0.0.1... * Adding handle : conn : 0x7fb32c004000 * Adding handle : send : 0 * Adding handle : recv : 0 * Curl_addHandleToPipeline : length : 1 * - Conn 0 ( 0x7fb32c004000 ) send_pipe : 1 , recv_pipe : 0 * Connected to 127.0.0.1 ( 127.0.0.1 ) port 8080 ( #0) > GET / HTTP / 1.1 > User - Agent : curl / 7.30.0 > Host : 127.0.0.1 : 8080 > Accept : */* > < HTTP / 1.1 404 Not Found < Content - Type : application / json < Content - Length : 56 < Date : Mon , 03 Nov 2014 04 : 58 : 27 GMT < Connection : keep - alive < * Connection #0 to host 127.0.0.1 left intact { "code" : "ResourceNotFound" , "message" : "/ does not exist" }

This shows that the status code is a 404.

Now let’s move on and register some route handlers!

Set Up Your Things Database

In a real world situation you would use a proper database engine, such as MongoDB or PostgreSQL. For the simplicity of this demo we will create a simple in-memory database that only lives for the duration of the server. Create a file called things-db.js and place the following into it:

var uuid = require('uuid'); var _ = require('underscore'); module.exports = function createDatabase (options) { var baseHref = options.baseHref; var things = {}; function thingAsResource(thing){ var resource = _.extend({ href: baseHref + thing.id },thing); delete resource.id; return resource; } function thingsAsCollection(){ return Object.keys(things).map(function(id){ return thingAsResource(things[id]); }); } return { all: function(){ return thingsAsCollection(); }, getThingById: function(id){ var thing = things[id]; return thing ? thingAsResource(thing) : thing; }, deleteThingById: function(id){ delete things[id]; }, createThing: function(thing){ var newThing = _.extend({ id: uuid() },thing); var newRef = things[newThing.id] = newThing; return thingAsResource(newRef); } }; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 var uuid = require ( 'uuid' ) ; var _ = require ( 'underscore' ) ; module . exports = function createDatabase ( options ) { var baseHref = options . baseHref ; var things = { } ; function thingAsResource ( thing ) { var resource = _ . extend ( { href : baseHref + thing . id } , thing ) ; delete resource . id ; return resource ; } function thingsAsCollection ( ) { return Object . keys ( things ) . map ( function ( id ) { return thingAsResource ( things [ id ] ) ; } ) ; } return { all : function ( ) { return thingsAsCollection ( ) ; } , getThingById : function ( id ) { var thing = things [ id ] ; return thing ? thingAsResource ( thing ) : thing ; } , deleteThingById : function ( id ) { delete things [ id ] ; } , createThing : function ( thing ) { var newThing = _ . extend ( { id : uuid ( ) } , thing ) ; var newRef = things [ newThing . id ] = newThing ; return thingAsResource ( newRef ) ; } } ; } ;

Now we need to require this database in our server.js and create an instance of the database. Place this in your server.js file, just below the host and port declarations:

var thingDatabse = require('./things-db'); var db = thingDatabse({ baseHref: 'http://' + host + ( port ? (':'+ port): '' ) + '/things/' }); 1 2 3 4 5 6 var thingDatabse = require ( './things-db' ) ; var db = thingDatabse ( { baseHref : 'http://' + host + ( port ? ( ':' + port ) : '' ) + '/things/' } ) ;

This creates a database instance and tells it the base URL of the server so that it can assign the appropriate href to resources.

Set Up the GET Routes

Now that we have our DB instance setup, we can wire up a route handler to it. We’ll do the collection and single-resource URLs first, as they do not require any authentication. Insert these route handlers above your server.on statement:

server.get('/things',function(req,res){ res.json(db.all()); }); server.get('/things/:id',function(req,res,next){ var id = req.params.id; var thing = db.getThingById(id); if(!thing){ next(new restify.errors.ResourceNotFoundError()); }else{ res.json(thing); } }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 server . get ( '/things' , function ( req , res ) { res . json ( db . all ( ) ) ; } ) ; server . get ( '/things/:id' , function ( req , res , next ) { var id = req . params . id ; var thing = db . getThingById ( id ) ; if ( ! thing ) { next ( new restify . errors . ResourceNotFoundError ( ) ) ; } else { res . json ( thing ) ; } } ) ;

Restart your server ( Ctrl + C to kill the process in your terminal) and try it again with Curl. If you request the things collection you will get an empty collection (seen as empty array brackets):

curl http://127.0.0.1:8080/things [] 1 2 3 curl http : //127.0.0.1:8080/things [ ]

Trying to get a resource that does not yet exist will result in a 404 message:

curl http://127.0.0.1:8080/things/1 {"code":"ResourceNotFound","message":""} 1 2 3 4 curl http : //127.0.0.1:8080/things/1 { "code" : "ResourceNotFound" , "message" : "" }

Great! Now let’s actually create some things by setting up a POST handler for the collection. To do that, we need to setup authentication for the routes.

Pro trip: Use a file watecher like nodemon to automatically restart your server as you edit it.

Set Up Authentication

As mentioned above we will use the OAuth2 client credentials workflow. This means we need a POST handler for /oauth/tokens and some code to exchange the Basic Auth credentials for a JWT. We will also need a filter for any route that requires the JWT, so we can assert it’s existence and validity before allowing the rest of the route handlers to be processed.

To meet these requirements we will leverage Stormpath and its API Key authentication features. The Stormpath Node SDK contains a method on application instances, authenticateApiRequest , which does everything we just mentioned! To make it even easier we’ve wrapped that method in the stormpath-restify module as a filter so it’s even easier to use.

Gather Your Stormpath API Credentials and Application Href

We will be using Stormpath to manage our users and their API keys, and our server will need to communicate with the Stormpath API in order to do this. If you haven’t already signed up for a free Stormpath developer account you can get one at api.stormpath.com/register.

Like all APIs, the communication between your app and Stormpath is secured with an “API Key Pair”. You can download your API key pair as a file from your dashboard in the Stormpath Admin Console. Retain this file – we will use this in a moment.

While you are in the Admin Console you will need to get the href of your Stormpath Application. In Stormpath, an Application object is used to link your server app to your user stores inside of Stormpath. All new developer accounts have an app called “My Application”. Click on “Applications” in the Admin Console, then click on “My Application”. On that page you will see the href for the Application. Copy this — we will need it shortly.

Provide Your Credentials to your Restify Server

We don’t want to hard code our credentials into our server, because that’s not a good security practice. Instead we want to “put them in the enviornment”, which that something outside of the

server will supply them to the server. The most common way of doing this is to put them in environment variables, which you can do like this:

Unix/Linux/Mac:

export STORMPATH_CLIENT_APIKEY_ID=xxxx export STORMPATH_CLIENT_APIKEY_SECRET=xxxx export STORMPATH_APPLICATION_HREF=xxxx 1 2 3 4 export STORMPATH_CLIENT_APIKEY_ID = xxxx export STORMPATH_CLIENT_APIKEY_SECRET = xxxx export STORMPATH_APPLICATION_HREF = xxxx

Windows:

set STORMPATH_CLIENT_APIKEY_ID=xxxx set STORMPATH_CLIENT_APIKEY_SECRET=xxxx set STORMPATH_APPLICATION_HREF=xxxx 1 2 3 4 set STORMPATH_CLIENT_APIKEY_ID = xxxx set STORMPATH_CLIENT_APIKEY_SECRET = xxxx set STORMPATH_APPLICATION_HREF = xxxx

The stormpath-restify module knows to look for those variables.

You can also put the credentials in a yaml file, named stormpath.yaml , in the root folder of your project:

client: apiKey: id: xxxx secret: xxxx application: href: https://api.stormpath.com/v1/applications/xxxx 1 2 3 4 5 6 7 client : apiKey : id : xxxx secret : xxxx application : href : https : //api.stormpath.com/v1/applications/xxxx

You should make sure that this file is not added to git, because sensitive information should not be stored in Git. Here is a quick way, from your terminal, to list this file in the “git ignore” file:

echo "stormpath.yaml" >> .gitignore 1 2 echo "stormpath.yaml" > > . gitignore

There are many other ways to provide your credentials to Stormpath in addition to the two ways discussed above. You can learn more about alternative options in the Configuration section of our docs.

Add Stormpath to your Restify Server

In order to use these filters you will need to configure a “filter set”, this is a set of filters that are bound to your Stormpath Application. To create this filter set you need to add this to the top of your file, place it after the restify require:

var stormpathRestify = require('stormpath-restify'); var stormpathFilters = stormpathRestify.createFilterSet(); 1 2 3 4 var stormpathRestify = require ( 'stormpath-restify' ) ; var stormpathFilters = stormpathRestify . createFilterSet ( ) ;

The variable stormpathFilters is now an object with some other functions that you can use to create the necessary authentication filters. You can pass Stormpath Client options to createFilterSet() if needed, but in our case, we don’t need to do anything special because we have already put our credentials in the environment.

To use the Oauth filter, simply create a new one and assign it to a variable, you can paste this below the code we just did:

var oauthFilter = stormpathFilters.createOauthFilter(); 1 2 var oauthFilter = stormpathFilters . createOauthFilter ( ) ;

Now you can register a post handler which uses this filter as the only filter. Paste this after your server.use statements:

server.post('/oauth/token', oauthFilter); 1 2 server . post ( '/oauth/token' , oauthFilter ) ;

That’s it! If your API user posts a valid API Key pair to that URL, they will receive a token in exchange. If it’s not valid they will get a descriptive error.

Once your user has obtained a token they will use it to post a new thing. We’ll create a POST hander for this, and apply the Stormpath filter to it as well. This will check that the token is valid and if so allow the POST to continue into our handler. If the token is not valid, an error will be sent and our handler will not be reached. Here is the handler to paste in below your other routes:

server.post('/things', [oauthFilter, function(req,res){ res.json(db.createThing(req.body)); }]); 1 2 3 4 server . post ( '/things' , [ oauthFilter , function ( req , res ) { res . json ( db . createThing ( req . body ) ) ; } ] ) ;

Try It Out – Token Exchange

In order to try our new POST endpoint we need to do the token exchange and obtain a JWT.

At this point let’s pretend we are a consumer of our API and need to provision an account. Later we’ll discuss how to automate this, but for this first user you can head over to the Stormpath Admin Console and go to your “My Application” and create a dummy account in the Directory of that application. After creating the account, create an API Key pair (available on the Account details view).

Once you have the key pair, you can exchange those credentials for a JWT by using the new /oauth/tokens route on your server:

curl -u ACCOUNT_API_KEY:ACCOUNT_API_KEY_SECRET -X POST http://127.0.0.1:8080/oauth/token?grant_type=client_credentials 1 2 curl - u ACCOUNT_API_KEY : ACCOUNT_API_KEY_SECRET - X POST http : //127.0.0.1:8080/oauth/token?grant_type=client_credentials

You’ll get the following JSON response in your terminal with the “access_token” value:

{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0R05XMTNRUE5aMjlaS0JKQk02VE40RkM2IiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvMWg3MlBGV29HeEhLaHlzS2pZSWtpciIsImlhdCI6MTQxNDk5NDAxNiwiZXhwIjoxNDE0OTk0MDI2fQ.SaOJ6R8iX2fbNlr8eWTzydglZzFV14FtagrBjScBRdE","token_type":"bearer","expires_in":10,"scope":""} 1 2 { "access_token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0R05XMTNRUE5aMjlaS0JKQk02VE40RkM2IiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvMWg3MlBGV29HeEhLaHlzS2pZSWtpciIsImlhdCI6MTQxNDk5NDAxNiwiZXhwIjoxNDE0OTk0MDI2fQ.SaOJ6R8iX2fbNlr8eWTzydglZzFV14FtagrBjScBRdE" , "token_type" : "bearer" , "expires_in" : 10 , "scope" : "" }

Copy this “access_token” value and use it in your next request when you create a thing:

curl -X POST -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json;charset=UTF-8" -d '{"myThing":"isAnAwesomeThing"}' http://127.0.0.1:8080/things 1 2 curl - X POST - H "Authorization: Bearer YOUR_TOKEN_HERE" - H "Content-Type: application/json;charset=UTF-8" - d '{"myThing":"isAnAwesomeThing"}' http : //127.0.0.1:8080/things

The API should respond with the thing you’ve created, and its href identifier:

{"href":"http://127.0.0.1:8080/things/b70fd4d9-4a4f-43a7-a4ea-fb9e18e78b2c","myThing":"isAnAwesomeThing"} 1 2 { "href" : "http://127.0.0.1:8080/things/b70fd4d9-4a4f-43a7-a4ea-fb9e18e78b2c" , "myThing" : "isAnAwesomeThing" }

If we ask for the entire collection again, we will see it in the set:

curl http://127.0.0.1:8080/things [{"href":"http://127.0.0.1:8080/things/b70fd4d9-4a4f-43a7-a4ea-fb9e18e78b2c","myThing":"isAnAwesomeThing"}] 1 2 3 curl http : //127.0.0.1:8080/things [ { "href" : "http://127.0.0.1:8080/things/b70fd4d9-4a4f-43a7-a4ea-fb9e18e78b2c" , "myThing" : "isAnAwesomeThing" } ]

Pretty sweet, right? You’ve now got an API with authorization, resources and collections. But… working with Curl gets pretty clunky once you start dealing with tokens. We still need to build some other features into our API, but I want to switch over to the client library for a little while, so it’s quicker to use our API and ensure things are working as we expect.

Build the Client Library

As mentioned above, you should check out Les Hazlewood’s post on Designing Node API Clients. Our client library will look very similar: it abstracts how we interact with resources and collections and exports an API that is developer-friendly with well-named methods.

For our Things API we’re going to use Restify in the client as well. In addition to the server library we’ve built, Restify includes a client library you can use to build your own client. These great little clients do a lot of the underlying HTTP and content type work for you.

The stormpath-restify library includes an OAuth2 client that extends the JSON client with credential exchange and token work – all that stuff that we just did with Curl.

The client library for your API will be provided to your end-users as a node module, published on NPM, so we should create a new project for this. Create a new folder and do the npm init process, as we did for the server. I’ll call mine the “things-api” – a predictable name end-users will recognize when they look for a client for my service:

cd .. mkdir things-api cd things-api npm init npm install --save restify stormpath-restify underscore prompt touch index.js 1 2 3 4 5 6 7 cd . . mkdir things - api cd things - api npm init npm install -- save restify stormpath - restify underscore prompt touch index . js

We will use index.js as the entry point for this module, as it’s very straightforward. You may want something more elaborate as your client module evolves.

Paste this into your index.js as a starting point:

var oauthClient = require('stormpath-restify/oauth-client'); module.exports = { createClient: function(opts){ opts.url = opts.url || 'http://127.0.0.1:8080'; // This creates an instance of the oauth client, // which will handle all HTTP communication with your API var myOauthClient = oauthClient.createClient(opts); // Here we directly bind to the underlying GET method, // as this is a simple request myOauthClient.getThings = myOauthClient.get.bind(myOauthClient,'/things'); return myOauthClient; } }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var oauthClient = require ( 'stormpath-restify/oauth-client' ) ; module . exports = { createClient : function ( opts ) { opts . url = opts . url | | 'http://127.0.0.1:8080' ; // This creates an instance of the oauth client, // which will handle all HTTP communication with your API var myOauthClient = oauthClient . createClient ( opts ) ; // Here we directly bind to the underlying GET method, // as this is a simple request myOauthClient . getThings = myOauthClient . get . bind ( myOauthClient , '/things' ) ; return myOauthClient ; } } ;

With that you can now export a client that has a method, getThings , which gets all the things in the collection and returns them to the developer. Super simple. What does it look like for them to use this client library? We’ll cover that in the next section.

While the collection get is simple and can be directly bound to the underlying get method, the add thing method will have some more logic because we want to do some “client side” validation in order to assert that the data is correct before we even try posting it to the server.

Here is what that looks like, paste this into index.js after the getThings method but before the return statement:

myOauthClient.addThing = function addThing(thing,cb){ if(typeof thing!=='object'){ process.nextTick(function(){ cb(new Error('Things must be be an object')); }); }else{ myOauthClient.post('/things',thing,cb); } }; 1 2 3 4 5 6 7 8 9 10 myOauthClient . addThing = function addThing ( thing , cb ) { if ( typeof thing ! == 'object' ) { process . nextTick ( function ( ) { cb ( new Error ( 'Things must be be an object' ) ) ; } ) ; } else { myOauthClient . post ( '/things' , thing , cb ) ; } } ;

Build the Developer App

Before switching back to the server, let’s also build our developer demo app. This shows you how a developer would use your client library to consume your API. Create a new folder for this module and initialize it with dependencies and an app.js file:

cd .. mkdir developer-app cd developer-app npm init # use app.js as the main entry npm install --save prettyjson touch app.js 1 2 3 4 5 6 7 cd . . mkdir developer - app cd developer - app npm init # use app.js as the main entry npm install -- save prettyjson touch app . js

Now paste the following into your app.js:

// Here we use a local, relative require path to require your // client library. When you publish on NPM you should change // it to the absolute module name // Note: in practice, the developer should supply their API // Key and Secret through environment variables, and not // hard-code them here. var thingsApi = require('../things-api'); var prettyjson = require('prettyjson'); var client = thingsApi.createClient({ key:'ACCOUNT_API_KEY', secret:'ACCOUNT_API_KEY_SECRET' }); // Read all the things in the collection client.getThings(function(err,things) { if(err){ console.error(err); }else{ console.log('Things collection has these items:'); console.log(prettyjson.render(things)); } }); // Create a new thing in the collection client.addThing( { myNameIs: 'what?' }, function(err,thing) { if(err){ console.error(err); }else{ console.log('New thing created:'); console.log(prettyjson.render(thing)); } } ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 // Here we use a local, relative require path to require your // client library. When you publish on NPM you should change // it to the absolute module name // Note: in practice, the developer should supply their API // Key and Secret through environment variables, and not // hard-code them here. var thingsApi = require ( '../things-api' ) ; var prettyjson = require ( 'prettyjson' ) ; var client = thingsApi . createClient ( { key : 'ACCOUNT_API_KEY' , secret : 'ACCOUNT_API_KEY_SECRET' } ) ; // Read all the things in the collection client . getThings ( function ( err , things ) { if ( err ) { console . error ( err ) ; } else { console . log ( 'Things collection has these items:' ) ; console . log ( prettyjson . render ( things ) ) ; } } ) ; // Create a new thing in the collection client . addThing ( { myNameIs : 'what?' } , function ( err , thing ) { if ( err ) { console . error ( err ) ; } else { console . log ( 'New thing created:' ) ; console . log ( prettyjson . render ( thing ) ) ; } } ) ;

Look familiar? If you’ve used API clients before this definitely looks familiar – but this time YOU created it and it’s for your API 🙂

You can demo your app by invoking it in the Terminal (make sure that you have the server running in another terminal):

node app.js 1 2 node app . js

Round Out the Server – Delete for Trusted Users

We have one last handler to implement in the server, and that is the DELETE method for trusted users. We want users in the ‘trusted’ Group to be able to delete resources from the things collection.

We’re going to setup another filter, using Stormpath to help us out. stormpath-restify provides a group filter which allows us to assert that a user is in a given group, in this case a group called trusted (you can create this group in the Stormpath Admin Console. If the user is in the group, we pass control to your handler, otherwise we issue a 403 error response. If you wish to customize the error response, you can pass an errorHandler property to createGroupFilter , a function to receive the arguments (err,req,res,next) .

To create the trusted group filter, paste this below your other filter invocations:

var trustedFilter = stormpathFilters.createGroupFilter({ inGroup: 'trusted' }); 1 2 3 4 var trustedFilter = stormpathFilters . createGroupFilter ( { inGroup : 'trusted' } ) ;

This filter will assert that the authenticated user is in the trusted group.

Let’s use this new filter to setup our DELETE handler:

server.del('/things/:id',[oauthFilter,trustedFilter,function(req,res,next){ var id = req.params.id; var thing = db.getThingById(id); if(!thing){ next(new restify.errors.ResourceNotFoundError()); }else{ db.deleteThingById(id); res.send(204); } }]); 1 2 3 4 5 6 7 8 9 10 11 server . del ( '/things/:id' , [ oauthFilter , trustedFilter , function ( req , res , next ) { var id = req . params . id ; var thing = db . getThingById ( id ) ; if ( ! thing ) { next ( new restify . errors . ResourceNotFoundError ( ) ) ; } else { db . deleteThingById ( id ) ; res . send ( 204 ) ; } } ] ) ;

Now that the server can accept DELETE requests, we want to add a corresponding convenience method to our client. Paste this method into your client library (index.js), below the other methods but before the return statement:

myOauthClient.deleteThing = function deleteThing(thing,cb){ if(typeof thing!=='object'){ process.nextTick(function(){ cb(new Error('Things must be be an object')); }); } if(typeof thing.href!=='string'){ process.nextTick(function(){ cb(new Error('Missing property: href')); }); } myOauthClient.del(thing.href,function(err){ if(err){ cb(err); // If the API errors, just pass that along }else{ // Here you could do something custom before // calling back to the original callback cb(); } }); }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 myOauthClient . deleteThing = function deleteThing ( thing , cb ) { if ( typeof thing ! == 'object' ) { process . nextTick ( function ( ) { cb ( new Error ( 'Things must be be an object' ) ) ; } ) ; } if ( typeof thing . href ! == 'string' ) { process . nextTick ( function ( ) { cb ( new Error ( 'Missing property: href' ) ) ; } ) ; } myOauthClient . del ( thing . href , function ( err ) { if ( err ) { cb ( err ) ; // If the API errors, just pass that along } else { // Here you could do something custom before // calling back to the original callback cb ( ) ; } } ) ; } ;

This method ensures the developer is passing an actual thing object, with an href, before making the request of the server.

At this point your developer can use the client to delete things:

client.deleteThing(thing,function(err){ if(err){ console.error(err); }else{ console.log('Thing was deleted'); } }); 1 2 3 4 5 6 7 8 client . deleteThing ( thing , function ( err ) { if ( err ) { console . error ( err ) ; } else { console . log ( 'Thing was deleted' ) ; } } ) ;

Again, thing should have the format:

{ myNameIs: 'what?', href: 'http://127.0.0.1:8080/things/ID' } 1 2 { myNameIs : 'what?' , href : 'http://127.0.0.1:8080/things/ID' }

If you haven’t created the trusted group yet, or haven’t added the account to it, you will get the 403 error when we try to delete the item. To create the group and add the user to it you can use the Stormpath Admin Console or our Node SDK to talk directly with the API to create the group and the account membership

How To Provision Your API Keys

The last thing to discuss is how to provision API Keys for your end developers. Clearly you wouldn’t want to use the Stormpath Admin Console to create every API Key pair. Instead, you’ll want to automate this process.

From a product perspective, I suggest you offer a web-based landing page where someone can create an account and then view a dashboard where they can provision their own API keys.

Stormpath can help with this process as well. We have great workflows around account creation and email verification. For building the web-based component of your registration workflow, I suggest trying out our express-stormpath library. Yes, I am suggesting that you use Express for this – and that’s because Express is designed for that! It’s totally normal to have one sever for your API and one for your web app(s). In fact, it’s encouraged: for a good read check out the Twelve-factor App

However! I don’t want to leave you hanging, so I’ll show you a very simple way to allow developers to obtain an API key, but only after they have verified their email address.

In order to enable email verification, please log into the Stormpath Admin Console and visit the Workflows section of the directory in your default “My Application”.

After the workflow is enabled, we will implement another route handler to leverage two more Stormpath filters. Create them below your other filter invocations:

var newAccountFilter = stormpathFilters.newAccountFilter(); var accountVerificationFilter = stormpathFilters.accountVerificationFilter(); 1 2 3 var newAccountFilter = stormpathFilters . newAccountFilter ( ) ; var accountVerificationFilter = stormpathFilters . accountVerificationFilter ( ) ;

Then we’ll use those filters with two new routes:

server.post('/accounts',newAccountFilter); server.get('/verifyAccount',accountVerificationFilter); 1 2 3 server . post ( '/accounts' , newAccountFilter ) ; server . get ( '/verifyAccount' , accountVerificationFilter ) ;

These routes will allow users to post their email, password, and other required user information to create an account. To make that easier, let’s create a quick command line tool developers can use to register for our API service.

Command-line Registration Tool

Since we’re not building a full-blown web app for handling account creation, we’ll create a small command-line utility instead. I’ve created an example of how you might do this, but it’s a pretty large file so I won’t inline it here. You can get the source here: register.js source

This register.js file leverages the prompt library to do the following:

Prompt for first name, last name, email and password

Send that information to our API

Re-prompt for a new email if it already exists

Re-prompt for a new password it it’s not strong enough

Inform the user to check their email if creation is successful

Switch back to the things-api directory and copy the source of that file into a register.js file in your client module. Then modify the package.json for your client library to have this configuration:

{ "bin" : { "register" : "./register.js" } } 1 2 3 4 { "bin" : { "register" : "./register.js" } }

With that configuration, you can tell your developers to execute this command after they’ve installed your client module in their application:

./node_modules/.bin/register 1 2 . / node_modules / . bin / register

If you haven’t published your module to NPM you can still try this CLI tool by running it from inside the things-api directory:

node register.js 1 2 node register . js

Doing this will bring up the registration CLI:

Stormpath will send an email to the given email address, with a link that will retrieve an API Key Pair. You want to customize the email message to point to the /verifyAccount URL that we created in the API server. You can configure the email in the Stormpath console: “My Application” –> Directory –> Workflows. Then configure the message like this, making sure you set the Base URL to your local development app:

With that email template, your API users will receive a confirmation email:

Because we configured the email template to point to our server, when the user clicks on the email link they will land on our Restify server, where the Stormpath filter will kick in. It will verify that this link was actually generated by Stormpath, and if valid it will create an API key pair for the user and show it to them:

Your developer can then take those keys and start using them with your client library. Success!

The Proverbial “Me”

One last piece of awesome: the /me route. This very common route in APIs lets the consumer know who they are currently authenticated as.

Setting this up in the server is incredibly simple. The stormpath-restify library will attach the Stormpath account to req.account if the user is successfully authenticated. Thus, we just need a simple route handler:

server.get('/me',[oauthFilter,function(req,res){ res.json(req.account); }]); 1 2 3 4 server . get ( '/me' , [ oauthFilter , function ( req , res ) { res . json ( req . account ) ; } ] ) ;

Adding a convenience method to the client library is equally simple because it’s just a simple get request:

myOauthClient.getCurrentUser = myOauthClient.get.bind(myOauthClient,'/me'); 1 2 myOauthClient . getCurrentUser = myOauthClient . get . bind ( myOauthClient , '/me' ) ;

That allows our developers to do this in their application:

client.getCurrentUser(function(err,user) { if(err){ console.error(err); }else{ console.log('Who am I?'); console.log(user.fullName + ' (' + user.email + ')'); } }); 1 2 3 4 5 6 7 8 9 client . getCurrentUser ( function ( err , user ) { if ( err ) { console . error ( err ) ; } else { console . log ( 'Who am I?' ) ; console . log ( user . fullName + ' (' + user . email + ')' ) ; } } ) ;

Wrap It Up

And with that… we have built a fully-functional API, complete with registration and API Key distribution – go forth and build more API!

I hope you have learned a bit about the OAuth2 client credentials flow. I also hope I’ve shown you how easy it is to use Stormpath to implement that flow in your API, so you can get on with what you really want to do – writing your API endpoints.

If you’d like to learn more about our Restify integration please head over to stormpath-restify on Github.

If you want to dig even deeper into Stormpath you should check out the Stormpath Documentation as well as the Stormpath Node.JS SDK

For help with all Stormpath libraries and integrations, just hit us up on [email protected]. We’re happy to help!

####Like what you see? Follow @goStormpath to keep up with the latest releases.