Today, I’m going to walk you through everything you need to know in order to build a secure API service with Express.js and Stormpath.
Specifically, I’ll walk you through building a simple Express.js API, and then locking it down via HTTP Basic Authentication, and OAuth2 Client Credentials authentication. These two authentication protocols allow you to build secure server-to-server API services.
So, let’s do this!
But First! What are Basic Auth and OAuth2?
When you’re securing an API service for use by server-side applications, you’ll typically be choosing between two authentication protocols: Basic Authentication or OAuth2 Client Credentials.
HTTP Basic Authentication is a very old, and popular protocol. The way it works is simple:
- Each developer is given an API key to access your service.
- For every API request the developer makes, they’ll send along this API key to identify and authenticate themselves.
Simple.
Now, OAuth2 Client Credentials is a much newer protocol that is slightly more secure than HTTP Basic Authentication, but works in a similar manner.
- Each developer is given an API key to access your service.
- The developer makes a special request to your API service using their API key to obtain a temporary “Access Token”. This “Access Token” expires after a short amount of time (usually an hour or so).
- Then, the developer sends this “Access Token” to your API service on every request, in order to identify / authenticate.
The OAuth2 protocol is slightly more secure than Basic Auth, as it doesn’t require the developer to send their confidential API key over the public internet as frequently, thereby reducing the chance of leaking confidential information.
In general:
- If you’re building an API service where security is a major concern, use OAuth2.
- If you’re building an API service where security is still important, but convenience is also important: use Basic Auth.
Building a Simple Express.js API
Before we get into the authentication part, let’s build a simple Express.js API service that we can use to secure later.
To get started, create a new folder somewhere, we’ll use this for our example:
1 2 3 |
mkdir example cd example |
Next, install express, as well as express-stormpath (which we’ll use for authentication later on):
1 2 |
npm install express express-stormpath |
Finally, create a new file: server.js
, in which we’ll place our Express.js code:
1 2 3 4 5 6 7 8 9 10 11 12 |
'use strict'; var express = require('express'); var app = express(); app.get('/api/test', function(req, res) { res.json({ test: 'successful!' }); }); app.listen(3000); |
The small API service above exposes a single endpoint: /api/test
, which just returns a simple JSON message. If you run the above API service using node:
1 2 |
node server.js |
And then run the following curl command to test the API endpoint — you’ll see that things work as expected:
1 2 3 |
curl http://localhost:3000/api/test {"test": "successful!"} |
Want to learn more about the Node backend? We take a deeper dive into mobile app development using Node.js for REST APIs in this post.
Getting Set Up with Stormpath
Now that we’ve got an API service we’re ready to secure, let’s create a Stormpath account. Stormpath is an API service that stores user accounts securely, and provides open source libraries that make it easy to build secure websites and API services =) Andddd, it’s also 100% free!
So, to create a Stormpath account, go and sign up here.
Next, you need to create a Stormpath API key. You can do so by visiting the Dashboard page, and generating an API key:
Once you’ve created / downloaded a Stormpath API key, place it into your project folder with the name apiKey.properties
:
1 2 |
cp ~/Downloads/apiKey-* apiKey.properties |
NOTE: Do NOT check the apiKey.properties
file into version control. This file holds your confidential Stormpath API keys, so making it publicly accessible would be an enormous security concern!
Finally, create a new Stormpath Application for this example app. Typically, each project you have will require it’s own unique Stormpath Application:
Once you’ve created a new Stormpath Application, copy the Application href
, we’ll need this in a moment.
Now that we’ve got our Stormpath stuff set up, let’s initialize the Stormpath express library in our code — here’s the new source:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
'use strict'; var express = require('express'); var stormpath = require('express-stormpath'); var app = express(); app.use(stormpath.init(app, { application: { // This href should be copied from the href of the Stormpath Application you // created. href: 'https://api.stormpath.com/v1/applications/xxx' } })); app.get('/api/test', function(req, res) { res.json({ test: 'successful!' }); }); app.on('stormpath.ready', function() { app.listen(3000); }); |
All we have to do here is make a couple minor modifications:
- Initialize the Stormpath middleware, telling Stormpath what Application to use.
- Start the Express.js webserver only after the Stormpath library has been fully initialized.
Now, with the modifications we made, all we’ve done is initialize Stormpath — we haven’t yet secured our API.
We’ll get to that in the next section =)
Securing an API with Stormpath
To secure an API with Stormpath, you really only need to include one simple middleware. Here’s our test route, from above, re-written to enforce API authentication:
1 2 3 4 |
app.get('/api/test', stormpath.apiAuthenticationRequired, function(req, res) { res.json({ test: 'successful!' }); }); |
The only difference from before? We’ve included the stormpath.apiAuthenticationRequired
middleware. This middleware looks at the HTTP Authorization header on incoming requests, and authenticates a user based on their API credentials (either using Basic Auth or OAuth2), and only once a user has authenticated, allows them to access the route.
Let’s see what happens if we retry our unauthenticated curl request from
earlier:
1 2 3 |
curl http://localhost:3000/api/test {"error": "Invalid API credentials."} |
As you can see, we’re now getting an error (if you look at what headers are returned, you’ll notice we’re also getting an HTTP 401 UNAUTHORIZED response).
Now, assuming we want to deploy our API live into production right now, all we’d need to do is serve our API over HTTPs — and we’d have a secure API service!
In the next section, we’ll go over how you can manage users, API keys, and actually authenticate to your newly secured API service.
Managing Stormpath Users / API Keys
So, now that we’ve got a secure API, let’s go ahead and create a user account in our Stormpath Application — this way we have a user who can eventually authenticate against our API.
Usually, you’d create users by building a registration / login page (our Express.js library can do that for you!), but for now, I’ll show you how to manually create users.
First off, go to your newly created Stormpath Application from the “Applications” page in your dashboard.
Next, click the “Accounts” on the left of your screen. From this page, you can manually create a user account:
Once you’ve created a new user Account, scroll to the bottom of your new Account, and open up the API Keys tab. In Stormpath, each Account can have as many API keys as they want — so if you’re building an API service, Stormpath will securely generate API keys for your users.
Click the “Create API Key” button to generate a new API key for this user. This will download the user’s new API credentials so we can use them later:
That wasn’t too bad, right? With a few clicks we were able to create user accounts, and API keys for our users.
In the next section, we’ll talk about how to authenticate against our new API using our API credentials.
Authenticating Against an API Service
First, let’s talk about the most simple form of API authentication: Basic Auth!
Basic Auth is my favorite form of API authentication because it’s very simple, and most developers are familiar with it.
With Basic Authentication, a developer will send their API key to your API service on each request they make, in order to authenticate.
When we generated an API key for our user in the previous section, we downloaded an API key file.
If we open this file up, we should see some API credentials:
1 2 3 4 |
cat ~/Downloads/apiKey-* apiKey.id = 4IEQNP0M0LOYMEPUILUI932XM apiKey.secret = FOklNg4GqRFRAhK3XCfgN1uLXBGii7dk0oQ3HMjzSfg |
To use these credentials to authenticate against our API with Basic Auth, we can generate a curl command like so:
1 2 3 |
curl --user 4IEQNP0M0LOYMEPUILUI932XM:FOklNg4GqRFRAhK3XCfgN1uLXBGii7dk0oQ3HMjzSfg \ http://localhost:3000/api/test |
The --user
flag tells curl to put our API credentials into Basic Auth format.
Easy right?
If you run the above curl command, you’ll see that now you’re able to successfully authenticate and get the original JSON response back! Yey!
Now, let’s talk about OAuth2 Client Credentials.
The OAuth2 protocol provides several different authentication mechanisms — but the type you want to use when building a server-to-server API is the Client Credentials type.
This flow basically works like so:
- A developer exchanges their API key for a temporary Access Token using your API.
- The developer then uses this Access Token to authenticate against your API service.
This is a bit more secure than Basic Auth, because developers are not sending their API keys to your service on every request — instead, they’re sending a temporary access token only.
To generate an Access Token, we’ll first need to exchange our API key for an Access Token using the Stormpath library:
1 2 3 4 5 6 7 8 9 10 11 |
curl --user 4IEQNP0M0LOYMEPUILUI932XM:FOklNg4GqRFRAhK3XCfgN1uLXBGii7dk0oQ3HMjzSfg \ --data 'grant_type=client_credentials' \ -X POST \ http://localhost:3000/oauth/token { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0SUVRTlAwTTBMT1lNRVBVSUxVSTkzMlhNIiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvdkx0eEYzMWdRazU5NzdxYmJTY2MzIiwiaWF0IjoxNDQ5NjIxODY1LCJleHAiOjE0NDk2MjU0NjUsInNjb3BlIjoiIn0.dZG4pDzZnrvSIHnY5wSYT0dqDauXAPx2IxdOHgmYBms", "token_type": "bearer", "expires_in": 3600, "scope": "" } |
By sending the above API request to /oauth/token
(a route provided by the Stormpath library automatically), you’ll get back a temporary Access Token as shown above.
Now that we have an Access Token, let’s use it to authenticate against our API endpoint!
1 2 3 |
curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0SUVRTlAwTTBMT1lNRVBVSUxVSTkzMlhNIiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvdkx0eEYzMWdRazU5NzdxYmJTY2MzIiwiaWF0IjoxNDQ5NjIxODY1LCJleHAiOjE0NDk2MjU0NjUsInNjb3BlIjoiIn0.dZG4pDzZnrvSIHnY5wSYT0dqDauXAPx2IxdOHgmYBms' \ http://localhost:3000/api/test |
If you run the above code sample with your Access Token, you’ll see that your request will be successfully authenticated!
Summary
To summarize: it’s quite simple to secure a REST API using both HTTP Basic Auth as well as OAuth2 Client Credentials. By writing middleware which inspects the HTTP Authorization header and looks for user credentials, then authenticates the incoming request properly, you can build a secure API service without too much trouble.
If you’d like to learn more about how the Stormpath express library works, and how to use it, be sure to check out the official documentation.