Integrating to Facebook, Google, and other social providers can be a pain. Do you want to deal with Facebook and Google tokens and their idiosyncrasies every time you build a new app? Probably not.
We at Stormpath frequently get requests to automate social login and integration for our customers so that they don’t have to build it themselves. Well, we’ve done that— Hooray! This post is about some of the design challenges and solutions we worked through while implementing this feature for our customers.
Social Login with Stormpath – Quick Description
Stormpath’s first OAuth integration makes it easy to connect to Google and Facebook in one simple API call. It’s a simple and secure way to retrieve user profiles and convert them into to Stormpath accounts so that no matter the service you’re using, you have one simple user API.
Goals and Design Challenges
My primary goal was to make this easy for developers. At the same time, it needed to be robust enough so that Stormpath could use it as the foundation to integrate with future identity providers like Twitter and GitHub.
This came with some design challenges:
How Do We Model Social Account Data in Stormpath?
We decided to let users configure external providers (like Google or Facebook) as a Stormpath Directory. In Stormpath, a Directory is a high-level ‘bucket’ of users and groups. Adding social integration at the Directory level means that all Facebook identities would exist in a Facebook directory— same for Google. This give a developer two big benefits:
You can map your Facebook or Google Directory to multiple applications in the same domain, allowing your apps to share those users without any additional code and improving your user experience.
You can define authorization policies for your social identities by assigning specific groups, roles, and permssions to them. Note— this particular feature is coming soon.
What Fields Should the Developer be Able to Update in a Social Account?
Google and Facebook do not allow you to write changes back to one of their accounts. This poses a problem. How do you add your own app-specific data to the record? As a solution, Stormpath creates a “mirror” of a social identity and allows you to add your own data to the “mirror” record via customData.
Do We Allow Password Resets?
Many applications with social integration rely solely on the external credentials hosted on the social network. This poses another problem. What if your registers with Google or Facebook but they later forget and try to log in directly with a username and password? This scenario is extremely common and often creates user confusion. They try all the passwords they remember and then eventually try a password reset, before finally contacting your help desk. At scale, this can clog your support staff.
To solve this problem, Stormpath allows you to create a new password for a social account in Stormpath. If you want, the user can specificy a password upon first registering and/or by initiating a password reset flow. Ultimately, the user can now choose how they want to log in regardless of how they registered.
How Do We Sync Data?
You can pull in profile data from social integrations and host it in Stormpath, but how do we keep the account information up-to-date without eating through a bunch of API calls? We decided to perform “on demand sync” – every time a user accesses your application with their social credentials, their Stormpath account information will be automatically updated with the information retrieved by the social provider.
How Will the Application Know the Difference Between New and Existing Social Accounts?
When retrieving an account from a social provider, you can tell whether the account is new to your application or if it already existed by checking the HTTP response status code. Stormpath will return a 201 Created status for newly obtained social accounts and a 200 OK when returning an existing/known account.
Making Google Access Tokens Painless
Getting an access token for a Google user in a web server application is not as easy as one might hope. Once the end-user has authorized your application, Google will send an “authorization code” as query parameter to the “redirect_uri” you specified in the developers console when you created your “Google project”. Finally, you’ll have to exchange the “authorization code” for an access token.
Of course, each of these calls require their own set of headers, parameters, etc. Fun times.
We wanted to reduce this burden for developers, so our Google integration conveniently automates the “exchange code” flow for you. This allows you to POST the authorization code and then receive a new (or updated) account, along with the access token, which can be used for further API calls.
Security
At Stormpath one of our main responsibilities is securing user data. When it comes to social integration, we ensure that Facebook and Google client secrets are encrypted using strong AES 256 (CBC) encryption, using secure-random Initialization Vectors. Every encryption key is tenant-specific, so you can guarantee that your encrypted secrets are only accessible by you.
Also, Facebook Login Security recommends that every server-to-server call is signed to reduce the risk of misuse of a user access token in the event it’s stolen. If your access token and you don’t require all your server calls to be signed, the thief can use your application as spam or read user’s private data.
Securing Facebook requests makes your application less vulnerable to attacks, and that’s why we recommend you to enable the Require proof on all calls setting for your Facebook application. Stormpath does this by default.
How does this work? Signing a call to Facebook just means adding the “appsecret_proof” parameter to every server request you make.
The content of the additional parameter is the hash value (SHA-256) of the user’s access with the Facebook application secret. Finally, the generated bytes are encoded using Hexadecimal characters.
How To Get Started With Stormpath Social Integration
To use Google or Facebook with Stormpath, follow these three steps:
Create a Facebook or Google Directory in Stormpath to mirror social accounts. You can do this via the Stormpath Admin Console, or our REST API using a POST like this:
12345678910111213
POST https://api.stormpath.com/v1/directories?expand=provider
Content-Type: application/json;charset=UTF-8
{
"name" : "my-google-directory",
"description" : "A Google directory",
"provider": {
"providerId": "google"
"clientId":"857385-m8vk0fn2r7jmjo.apps.googleusercontent.com",
"clientSecret":"ehs7_-bA7OWQSQ4",
"redirectUri":"https://myapplication.com/authenticate"
}
}
Assign the created directory to your application in Stormpath.
Populate your directory with social accounts from Google or Facebook using the application’s accounts endpoint.
That is it! Your application can now access social accounts. And you didn’t have to touch any OAuth!
Future Stormpath releases will support additional social account providers. Please give us your feedback and let us know which ones we should release next!
Node is blowing up! I’ve been working and playing with Node since 2010 and in that time I’ve seen it go from a tiny community of people hacking side projects to a full-fledged and legit movement of modern developers building very real, very important, and very large applications. A whole ecosystem of solutions has sprung up to help Node developers, and that ecosystem is rapidly evolving. But it’s increasingly hard to figure out what solutions are best for you because of all the noise in a Google search or in npm.
Authentication and user management in particular is a difficult and shifting landscape. And yet, when building a real application in Node, it is one of the first components you need to figure out. This guide aims to give you a complete lay of the land for user management and authentication in node.
What is available in Node?
Node today has several different paths to build user management. In no particular order there are:
Passport.js / Everyauth
Your Own Database and a Hashing Algorithm
User Management as a Service
Passport.js / Everyauth
PassportJS and Everyauth are authentication middleware for node that leverage the Connect middleware conventions. That means if you are using a framework like Express, Restify, or Sails you can easily plug one of their authentication schemes (or strategies) directly into your application. Everyauth comes with their strategies embedded, where as with Passport you can pick and choose which strategies to use. Some of the common strategies that developers use with Passport are Facebook and Google, but it also include everything from a local username/password authentication, to a slew of OpenID and OAuth providers, and even a Stormpath strategy for Passport.
Even though Everyauth and Passport are built on top of the same middleware framework, they have their own sets of pros and cons. Passport is more flexible and modular, but Everyauth provides additional functionality that helps with routes and login/registration views. For a lot of Node developers Passport is also preferred because it does not use promises.
Since Passport and Everyauth are built on Connect, both will help you with session management, including:
Serialization of the authenticated user
Managing the session
Logging the user out
Additionally, they are designed for simple, easy authentication, but fall short (by design) of broader user management needs. You are still left to design, implement, and maintain all your other user infrastructure.
For example, if you are using passport-local (the strategy to authenticate username / password against your own database), Passport does not handle user signup and account verification. You will need to work with database modules to authenticate to a database, create the account, track verification status, create a verification token, send an email, and verify the account. This means a developer will need to worry about URL safety, removing expired tokens, and other security constraints (like hashing the password correctly in a database).
Your Own Database and a Hashing Algorithm
The do-it-yourself approach doesn’t rely on any middleware. You choose your own stack, a database to store users (likely PostgresSQL and MongoDB) and a hashing algorithm to generate password hashes (likely bcrypt and scrypt). Searching for bcrypt or scrypt in npm will result in quite a few modules of varying degrees of quality, each with their own sets of dependencies. Be particularly careful if you are a Windows developer – we recommend the native JS implementation of bcrypt.
After deciding on a stack, you will need to build out user management and authentication. Historically this approach has been extremely common, but is tedious, prone to error, and requires more maintenance than other approaches.
You will need to build/figure out:
Account Creation
Create a user schema to hold user data
Create accounts and store salt + hashed passwords using bcrypt / scrypt
Sending an email with token for account verification
Account Authentication
Authenticate the user (comparing hashes)
Account Management
Password reset work flow
Generating / invalidating tokens
Role-based access / permissions
Integrations with ID and Social Providers
Secure the system
Secure the Database from unauthorized access
Secure the OS from unauthorized access
Backups for data
One of the biggest challenges with rolling your own auth and user management, is the maintenance. Take password hashing as an example. Done right, you select a cost factor that makes your hashing algorithm purposely slow (roughly 300-700ms) to prevent brute force attacks. However, Moore’s Law is a bitch— compute price/performance doubles every year. So the right cost factor today, may be considered insecure tomorrow. If you’re building applications that will go into production, its your responsibility to update your hashing strategy at least once a year.
Despite the Node community’s aversion to “rolling your own” middleware, there are a few benefits to this approach. You get complete control of your infrastructure. If the tools available to you are not “good enough” for what you need to deliver to your customer, then you have the ability to invest engineering effort and time to innovate around user authentication and user management. Luckily, very few applications and developers have those kind of requirements, so the open source tools and API services available today help them move faster and deliver more.
User Management as a Service
Over time, software has moved from on premise, to the cloud, to distributed API services. At the same time, development teams have come to rely on open source software and API services as much as their own code. It is now possible to offload user management to a system that exposes user management functionality via REST APIs and open-source SDKs for application development. Stormpath falls into this category along with some user API startups. The Node community, in particular, has adopted this service oriented paradigm more than any other community to date.
Typically, API-driven services allow for more common functionality around user management, going beyond just authentication. The additional functionality varies by provider, but usually includes:
Account email verification
Password reset work flows
Role based access / permissions
Schema-less User Profiles
Two-factor authentication
Single sign on between applications
Social login integration (Facebook, Google, etc)
Integration to Node auth middleware like Passport
In addition to pure features, they also off-load much of the security and operations. They host all the infrastructure for you, scale to absorb your peak traffic, and handle on-going security of your user data.
Offloading to an API service generally delivers convenience and improved security, while reducing development and maintenance costs. Developers now get to focus on building unique parts of their application.
However, there are trade-offs with using API services. You are introducing a 3rd party dependency to your application. It needs to be highly available, fast, portable, provide security during transport, and be flexible enough to meet your user data model.
Availability and performance are extremely important because a critical system like user authentication and management can not be offline or slow. Caching in their SDKS and being based on modern cloud infrastructures is a good start, but it is important that the service is prepared for the worst case scenarios – like whole data centers going down. And if you build on top of a service for user management, make sure you can subscribe to notifications of any outages.
Data portability is also critical – can you move user data in and out in safe (and easy) ways. While its easy to write a script to port unencrypted data over JSON, the ease of porting passwords will heavily depend on how you have stored any pre-existing data. For example, bcrypt is very portable by design, as it follows Modular Crypt Format (MCF). It is possible for multiple systems and languages to understand how to construct the hash by looking at the hash value itself. If you’re building a prototype and don’t use a service like Stormpath, we recommend starting with an MCF hash like bcrypt – it will be much easier to upgrade in the future.
Transport security between your application and the API Service is important in this approach compared to the approaches above. The additional network communication needs to be secured. For example, Stormpath supports only HTTPS and uses a custom digest auth algorithm to guard against replay and man in the middle attacks. You can read more about our security here.
The data model used by authentication services can vary widely – Salesforce, for instance, looks very different from the Stormpath data model, which is based on directories and therefore generic and flexibly. It’s worth digging in to make sure that the data model you have planned for your application, is supported by the service. This is particularly true for mulit-tenant applications or SaaS.
Additionally, documentation of APIs varies widely – you should make sure your solution outlines what you need before you dive in.
Building User Management…
…is hard. Inside node there are different solutions, each with a set of pros and cons. I hope this post helps you get the lay of the land. If you have any questions, suggestions or experiences that you want to share, feel free to leave a comment or reach out to me on twitter @omgitstom. And if you’re interested in a User Management API service, check out Stormpath and our Official Node SDK.
If you’re building a Node API client, the design of your client can make or break adoption.
Our CTO Les Hazlewood recently built the Stormpath Node SDK and put what he learned into this presentation on Building A Node.js Client for REST+JSON APIs. We get a ton of questions on how we design SDKs at Stormpath, so we put the video on Youtube.
In the video, Les covers:
Collection & Instance Resources
Public / Private API
Proxy Design
Component Architecture
Queries
Authentication – Digest Algorithm vs HTTP Basic
Pluggability
If you want to explore our Node client further, here’s the getting started code from the presentation:
Cryptography is an important part of almost every web or mobile application and yet most developers feel that they don’t understand it or worse, are doing it wrong. Yes, the field of cryptography is dominated by uber-smart mathematicians, researchers, and PhDs galore but thanks to the hard work of those people, we have great tools that the average dev can benefit from.
Here at Stormpath, our goal is to make developer’s lives easier and help them build more secure applications faster. Sharing the basics of cryptography will hopefully help you in your development projects.
What is Cryptography
Cryptography is the practice of protecting information from undesired access by hiding it or converting it into nonsense. For developers, cryptography is a notoriously complex topic and difficult to implement.
The goal of this guide is to walk you through the basics of Cryptography. How some of these algorithms and techniques are implemented is often dependent on your chosen language and/or framework but this guide will hopefully help you know what to look for. If you’re a Java developer, check out Apache Shiro. It’s a popular security framework thats makes implementing crypto much easier than messing with the JCE. ::cough:: We’re the authors.
Terminology
First, a bit of terminology. In crypto-land, you can break most algorithms down to ciphers and hashes.
Ciphers are algorithms that can encrypt or decrypt data based on shared or public/private keys.
Hashes (a.k.a. Message Digests) are one way, irreversible conversion of an input source. Often used for passwords and checksums.
When to use a Cipher vs a Hash
Put simply, you should use a hash when you know you will not need the original data in plain text ever again. When would you ever take data that you don’t ever need it’s original value? Well, passwords are a good example.
Let’s say Sean’s password is ‘Suck!tTrebek’. Your application doesn’t actually need to know the raw value of the password. It just needs to be able to verify that any future authentication attempt by Sean gives you a matching value. Hashes are great for that because the hash, while gibberish, will always be the same for a particular input, thereby letting you verify a match. Because you just need the hash to perform comparisons, the big benefit to you is that you don’t need to store Sean’s raw (plaintext) password directly in your database, which would be a bad idea.
Another example is a checksum. A checksum is a simple way to know if data has been corrupted or tampered with during storage or transmission. You take the data, hash it, and then send data along with the hash (the checksum). On the receiving end, you’ll apply the same hashing algorithm to the received data and compare that value to the checksum. If they don’t match, your data has been changed. This is one of the strategies Stormpath uses to prevent man-in-the-middle attacks on API requests.
Ciphers on the other hand are your tool if you will need the original raw value (called ‘plaintext’ in cryptography, even if its binary data) eventually. Credit card numbers are a good example here. Sean gives you his credit card and later you’ll need the plain text value to process a transaction. In order to encrypt and decrypt any piece of data you’ll need deal with keys and make sure you’re keeping them safe.
Working with Ciphers
Want to encrypt and decrypt your sensitive data like a boss? Let’s talk ciphers.
Choosing a Cipher Algorithm
If you’re reading this… well, then you should probably stick to AES-256 Encryption as it is approved by the US Military for top-secret material.
Most languages and many security frameworks support multiple cipher algorithms but determining which is appropriate for you is a complex topic outside the scope of this guide. Consult your local cryptanalyst.
Ciphers typically come in a few varieties. Symmetric or Asymmetric Ciphers. Symmetric ciphers can be further categorized into Block or Stream ciphers. Let’s discuss the differences.
Symmetric vs Asymmetric Cipher
Symmetric encryption (aka secret key encryption) uses the same (or trivially similar) key to both encrypt and decrypt data. As long as the sender and receiver both know the key, then they can encrypt and decrypt all the messages that use that use that key. AES and Blowfish are both Symmetric (Block) Ciphers.
But there could be a problem. What happens if the key falls into the wrong hands. Oh No!
Asymmetric ciphers to the rescue. Asymmetric encryption (aka public key encryption) uses a pair of keys, one key to encrypt and the other to decrypt. One key, the public key, is published openly so that anyone one can send you a properly encrypted message. The other key, the private key, you keep secret to yourself so that only you can decrypt those messages. Asymmetric sounds perfect, right? It has limitations too, unfortunately. It’s slower, using up more computing resources than a symmetric cipher and it requires more coordination between parties for each direction of communication.
Consider defaulting to asymmetric encryption until your project requirements suggest otherwise. And always remember to properly secure you private keys.
Block vs Stream Cipher
Symmetric ciphers can be categorized into two sub-categories: Block Ciphers and Stream Ciphers. A Stream Cipher has a streaming key that is used to encrypt and decrypt data. A Block Cipher uses a ‘block’ of data (a ‘chunk’ of bytes = a byte array) as the key that is used to encrypt and decrypt. We recommend most people use Block Ciphers since byte array keys are easy to work with and store. AES and Blowfish are both Block Ciphers for example.
Stream ciphers have their benefits (like speed) but are harder to work with so we don’t generally recommend them unless you know what you’re doing.
There’s a common misconception that Block ciphers are for block data like files and data fields while Stream ciphers are for stream data like network streams. This is not the case. The word ‘stream’ reflects a stream of bits used for the key, not the raw data (again, _plaintext) being encrypted or decrypted.
Securing Keys… Yes
Speaking of securing your keys, you should! No, I’m serious. If someone ever gets a hold of your private keys, all your encrypted data might as well be in plaintext. Like most everything in Cryptography, there are very advanced strategies but most are outside the skill set and budget of most developers. If you can afford key management software, then it’s your best and safest bet. Otherwise, you can still reduce some risk with basic strategies.
Keep your keys on another server and database than your encrypted data.
Keep that server’s security patches 100% up-to-date all the time (Firmware, OS, DB, etc).
Lock down its network access as much as you can. Invest in a good firewall.
Limit who on your team has access to the server and enforce multi-factor authentication for them to access it.
Working with Hashes
Don’t actually care what the original input value was but still need to do other things like matching? Let’s hash it out… get it?
Choosing a Hash Algorithm
Here too, most languages and many security frameworks support a variety of algorithms including MD-2, MD-5 and SHA-1, SHA-256, SHA-384, SHA-512, BCrypt, PBKDF2, and Scrypt. Unless you have a requirement for a particular hashing algorithm, we recommend you stick to BCrypt for secure data like passwords. It is a widely used and reviewed algorithm.
If you’ve heard of Scrypt before, then you’re probably wondering “Shouldn’t I be using Scrypt? Isn’t it better?” Maybe. Cryptanalysts are nothing if not paranoid (to our benefit). The prominent view among experts is that Scrypt is very promising but still too new to be considered a guaranteed bet for most people. So we recommend you stick with Bcrypt for now until more concrete research confirms SCrypt as better.
Salting and Repeated Hashing
For secure data, hashing is often not enough. The same message hashed will always have the same output and can therefore be susceptible to dictionary and rainbow table attacks.
To protect against these attacks, you should use salts. A salt is (preferably) randomly generated data that is used as an input to a hashing algorithm to generate the hash. This way, the same input message with two different salts will have different hashes.
Again, think of a password. If your password is 12345, then the hashed output would be the same anyone else who uses the same password (and very easy to guess for an attacker), unless the password is salted as well and each person has a different salt. Oh, and please don’t use the same salt for every record, that’s not a good idea. Different secure random salts for each password hash is a good idea.
In addition to salting, repeated hashing is recommended. Repeated hashing increases the time it takes someone to try to guess a password. For a user in human time, a difference of milliseconds to half a second is probably negligible. But to an attacker running a script with billions of password candidates, the added time per password can change the time it takes to attack a password from hours to years or even centuries! You’ll need to play with the appropriate number of iterations (or ‘rounds’ in BCrypt speak) in order to find the appropriate balance of security and performance.
What work factor (or # of iterations) should I use?
The complexity of your hashing algorithm comes down to performance versus security. If you’re talking about passwords, then a good rule of thumb is 500 milliseconds to process the algorithm on your production hardware. Most people won’t notice a half second delay during an authentication but it will make an attack prohibitively expensive for many attackers.
Keeping your Hashes and Ciphers up to date
The limiting factors to someone cracking your hashed or encrypted data is compute power and time. If a password is properly hashed with strong salts and a high number of iterations (work factor), it might take an attacker years to break a single password— today. With passwords in particular, you could have a high enough complexity factor so that it takes 0.5 to 1 second to process a password. But Moore’s law presents a problem. Every year compute power doubles and compute costs drop significantly. Moreover, new technologies pop up all the time that give attackers new advantages, like elastic on-demand compute clouds or power GPUs. So, what was a pretty secure hashing strategy today, may not be tomorrow. For any production application, you should be evaluating your strategy at least once a year and perhaps ratcheting up things like the number of hash iterations or salt sizes.
About Stormpath
Stormpath is a user mananagement API for developers. We make it easy to register, login, and manage users without build a database, worrying about data encryption or spending time on maintenance. Stormpath plugs into identity stores like Facebook, Google, LDAP and Active Directory, and also hosts robust user profiles.
I thought a great way to test out the new Stormpath node libraries would be to
build a simple website that allows you to do a few things:
Create a new account (register) with email and password.
Log into your new account (login) with email and password.
Display a dashboard page once you’ve logged in, that is only accessible to
users with an account.
Redirect unauthenticated users who try to access the dashboard back to the
login page.
Allow a logged in user to log out of their account (logout).
Pretty simple — but that should at least allow us to play around with the new
tooling!
In the end, things should look like this:
Sound good? I thought so!
Intro to Stormpath
If you aren’t already familiar with Stormpath, it’s an
API service that allows you to create, edit, and securely store your
application’s user accounts and user account data. Stormpath makes it easy to
do stuff like:
User registration and login.
Account verification via email.
Password reset via email.
Social login.
And a bunch of other cool stuff you probably don’t like coding!
So — why should you use Stormpath?
Well, quite simply, we make building user accounts a lot easier, more secure,
and more scalable than what you’re probably used to.
Using Stormpath not only allows you to easily build your application out, but it
also allows you to scale your site to support millions of users without changing
your code, or even needing a database!
So, let’s dive in.
If you don’t already have a Stormpath account and application, you’ll need to
create one now — you can do so here: https://api.stormpath.com/register
The rest of this article will assume you have a Stormpath account and API key
pair.
If you’re not familiar with express, you should check it out! express is an
awesome web framework for node.js which makes building full-fledged web
applications a lot simpler.
One of the most important pieces of express is the middleware layer (powered by
connect). This middleware allows you
to tap into HTTP requests before they reach your view code, allowing you to do
cool stuff like authenticate users, among other things.
Next up is passport. Passport is a generic library for handling user
authentication in node web apps. It allows you to abstract away some of the
technical details related to handling web session and authentication. We’ll be
using this in combination with the official passport-stormpath backend to log
users in and out of our new web app.
Lastly, we’ll also be using the official Stormpath node library to register new
users (essentially we’ll be sending Stormpath’s API service a POST request when
a new user creates an account, this way the user will be stored securely on
Stormpath’s servers).
Getting Started
So, now that we’ve covered what this web app will be doing, what it’ll look
like, and what we’ll use to build it: let’s get this going!
The first thing you need to do is install node.js (if you
don’t already have it installed).
Then, of course, you’ll want to go into your project directory and install all
of the basic dependencies:
12
$cd stormpath-express-sample
$ npm install
And that’s it for the basic configuration!
Configuration
Now that we have our skeleton application ready (thanks, express!), let’s change
our project name in the package.json file.
Open up package.json and change the name field so it says
"stormpath-express-sample" instead of "application-name". This will make
any errors we have easier to debug later on.
Install Required Modules
The next thing we’ll want to do is install all of the required modules we’re
going to be using.
You can install them all by running the following command:
NOTE: The --save flag instructs node to install the packages, and then add
them as dependencies to your project’s package.json file. This way, if you
want to bootstrap this project at a later time, you can do so easily by just
running npm install.
Set Environment Variables
Now that we’ve installed all the required modules, let’s configure our
environment variables.
We’re going to be using environment variables to tell our web app what
credentials / secrets to use when running our app.
You’ll want to create a .env file in the root of your project with the
following contents:
Obviously, you’ll need to replace these values with the appropriate values! The
Stormpath settings (API_KEY_ID, API_KEY_SECRET, and APP_HREF) will be used
to tell the app how to communicate with Stormpath. The EXPRESS_SECRET
variable is used to make session management secure (this should be a long string
of random characters).
If you haven’t already created a Stormpath application, you’ll want to go into
the Stormpath admin console and
create a new Application called stormpath-express-sample. Once you’ve created
this application, you should see an Application REST URL in the web interface —
use this URL as the value for your STORMPATH_APP_HREF environment variable.
Once you’ve got the environment variables defined in your .env file, all you
need to do is use them:
1
$source .env
The source command will run the .env file, setting the environment variables
in your current terminal session.
Configure Middleware
The next thing we need to do is open up the app.js file and import our
dependencies. You’ll want to make the top of your app.js file look like the
below:
123456789101112
varexpress=require('express');varpath=require('path');varfavicon=require('static-favicon');varlogger=require('morgan');varcookieParser=require('cookie-parser');varbodyParser=require('body-parser');// These are the new imports we're adding:varpassport=require('passport');varStormpathStrategy=require('passport-stormpath');varsession=require('express-session');varflash=require('connect-flash');
Now that we have our dependencies imported, let’s configure them!
In app.js, you’ll want to add the following:
1234567
varapp=express();// Here is what we're adding:varstrategy=newStormpathStrategy();passport.use(strategy);passport.serializeUser(strategy.serializeUser);passport.deserializeUser(strategy.deserializeUser);
Next, we need to configure some of our middleware in app.js:
Now we’re ready to move onto the good stuff: our routes.
Writing the Routes
Writing routes is where the real action happens.
We’re going to define several routes:
A / route which just displays a simple home page.
A /register route which renders a registration page. This route will need to
accept both GET and POST requests.
A /login route which will allow existing users to log in. This route will
need to accept both GET and POST requests as well.
A /logout route which will log users out of their account.
A /dashboard route which will display a dashboard page for logged in users.
To keep things orderly, let’s create two separate route files.
First, open up the routes/index.js file and replace its contents with the
following:
1234567891011121314151617181920
varexpress=require('express');varrouter=express.Router();// Render the home page.router.get('/',function(req,res){res.render('index',{title:'Home',user:req.user});});// Render the dashboard page.router.get('/dashboard',function(req,res){if(!req.user||req.user.status!=='ENABLED'){returnres.redirect('/login');}res.render('dashboard',{title:'Dashboard',user:req.user});});module.exports=router;
This index.js route file holds all of the main website routes (anything not
auth related).
Next, create a new file named routes/auth.js and add the following code:
varexpress=require('express');varrouter=express.Router();varpassport=require('passport');varstormpath=require('stormpath');// Render the registration page.router.get('/register',function(req,res){res.render('register',{title:'Register',error:req.flash('error')[0]});});// Register a new user to Stormpath.router.post('/register',function(req,res){varusername=req.body.username;varpassword=req.body.password;// Grab user fields.if(!username||!password){returnres.render('register',{title:'Register',error:'Email and password required.'});}// Initialize our Stormpath client.varapiKey=newstormpath.ApiKey(process.env['STORMPATH_API_KEY_ID'],process.env['STORMPATH_API_KEY_SECRET']);varspClient=newstormpath.Client({apiKey:apiKey});// Grab our app, then attempt to create this user's account.varapp=spClient.getApplication(process.env['STORMPATH_APP_HREF'],function(err,app){if(err)throwerr;app.createAccount({givenName:'John',surname:'Smith',username:username,email:username,password:password,},function(err,createdAccount){if(err){returnres.render('register',{title:'Register',error:err.userMessage});}else{passport.authenticate('stormpath')(req,res,function(){returnres.redirect('/dashboard');});}});});});// Render the login page.router.get('/login',function(req,res){res.render('login',{title:'Login',error:req.flash('error')[0]});});// Authenticate a user.router.post('/login',passport.authenticate('stormpath',{successRedirect:'/dashboard',failureRedirect:'/login',failureFlash:'Invalid email or password.',}));// Logout the user, then redirect to the home page.router.get('/logout',function(req,res){req.logout();res.redirect('/');});module.exports=router;
This auth.js route file contains all the routes that handle user-specific
stuff: registration, login, and logout.
Now that we’ve created our routes, we have to also plug them into the main
app.js file so they’ll be used by express.
First, remove the existing routes near the top of your app.js file:
123456
app.use(passport.session());app.use(flash());// Remove these two lines.varroutes=require('./routes/index');varusers=require('./routes/users');
Next, add in the following two lines to replace the ones you just removed:
After importing the routes, we’ll also need to bind them to express’ URL
routing mechanism:
123456
app.use(passport.session());app.use(flash());// Specify the routes here.app.use('/',index_routes);app.use('/',auth_routes);
Then, delete the existing routes that were there — the lines you’ll want to
remove are the following:
123
// Remove these two lines:app.use('/',routes);app.use('/users',users);
And with the changes above made — we’ve just successfully finished writing our
routes! In the next section, we’ll dive into understanding the routes, and
explain why things work the way they do.
Understanding the Routes
Now that we’ve defined our routes, let’s see how they actually work!
The Home Page Route
Let’s start by looking at the home page route:
1234
// Render the home page.router.get('/',function(req,res){res.render('index',{title:'Home',user:req.user});});
The home page route isn’t doing much other than rendering a template (which we
have yet to create!), and passing in some variable values.
The important thing to note here is the title and user values. We’ll use
the title variable in our template to generate a nice HTML title for the page.
We’ll also use the user variable to tell us whether or not the person viewing
the home page is a user or not.
If the person viewing the page IS a user, then instead of displaying a Login
button on the website, we’ll just display a link to the Dashboard page.
The req.user variable is automatically populated for us by passport. It will
either be undefined, or a JSON object of this user’s account.
The Dashboard Route
The dashboard route is also quite simple:
123456789101112
// Render the dashboard page.router.get('/dashboard',function(req,res){if(!req.user||req.user.status!=='ENABLED'){returnres.redirect('/login');}res.render('dashboard',{title:'Dashboard',user:req.user,});});
The first thing we’ll do here is check to see if the person viewing this page is
a user, and then, if their account is enabled or not (Stormpath allows you to
have users that disabled).
If the person viewing our dashboard page isn’t a valid user, we’ll redirect the
user to the login page.
If the person IS a valid user, we’ll render our dashboard page (simple —
right?).
The Registration Route
Now we’ll dive into the authentication routes. We’ll start by looking at our
registration route — which is responsible for signing up new users.
// Render the registration page.router.get('/register',function(req,res){res.render('register',{title:'Register',error:req.flash('error')[0]});});// Register a new user to Stormpath.router.post('/register',function(req,res){varusername=req.body.username;varpassword=req.body.password;// Grab user fields.if(!username||!password){returnres.render('register',{title:'Register',error:'Email and password required.'});}// Initialize our Stormpath client.varapiKey=newstormpath.ApiKey(process.env['STORMPATH_API_KEY_ID'],process.env['STORMPATH_API_KEY_SECRET']);varspClient=newstormpath.Client({apiKey:apiKey});// Grab our app, then attempt to create this user's account.varapp=spClient.getApplication(process.env['STORMPATH_APP_HREF'],function(err,app){if(err)throwerr;app.createAccount({givenName:'John',surname:'Smith',username:username,email:username,password:password,},function(err,createdAccount){if(err){returnres.render('register',{title:'Register',error:err.userMessage});}else{passport.authenticate('stormpath')(req,res,function(){returnres.redirect('/dashboard');});}});});});
The first bit just renders the registration page for GET requests.
The second bit is where things get interesting.
Firstly, we’re checking for a username and password field from the HTTP
form. This is what the user will be submitting to us when they create a new
account. (The username field is actually an email address, but I’ll
explain this in more detail later.)
Next, we’ll re-render the registration page (with an error message) if either
the username or password fields are missing.
After that’s out of the way, we need to initialize the Stormpath client. This
involves using our API key credentials to make a new client, and then fetching
our Stormpath application (since we’ll need to create this new user account
inside of our application namespace).
Once we’ve fetched our Stormpath application, we’ll then create a new user
account using the createAccount method. Since Stormpath requires (at
minimum):
givenName
surname
email
and password
fields — but we only want to store email / password — I’m just setting the
givenName and surname values to 'John' and 'Smith'.
NOTE: If the user account creation fails, we’ll render the registration
page and pass in an appropriate error message from Stormpath. This will
automatically handle problems like users attempting to register with an email
that already exists.
If everything goes smoothly, we’ll use the passport.js library to log this new
user in (creating a session, transparently), then redirect the user to the
dashboard page.
The Login Route
123456789101112131415161718
// Render the login page.router.get('/login',function(req,res){res.render('login',{title:'Login',error:req.flash('error')[0]});});// Authenticate a user.router.post('/login',passport.authenticate('stormpath',{successRedirect:'/dashboard',failureRedirect:'/login',failureFlash:'Invalid email or password.',}));
The login routes (shown above) are responsible for logging existing users back
into the site. The GET route only renders the login page, along with an
optional error message to display if a user enters invalid credentials.
NOTE: The req.flash('error')[0] you see is provided by the
connect-flash library. If a
login fails, the passport.js library will embed a tiny little ‘error’ message in
a cookie, which is what the req.flash('error')[0] call then retrieves.
The POST request is completely offloaded to the passport.js library. passport
provides the authenticate method which will transparently check the username
and password form fields against the Stormpath API, and take care of login
automatically.
If the login is successful, passport will redirect the user to the dashboard
page — otherwise, it’ll re-render the login page once more, along with a
friendly error message.
The Logout Route
12345
// Logout the user, then redirect to the home page.router.get('/logout',function(req,res){req.logout();res.redirect('/');});
The logout route (above) will log the user out of their account, destroying
their session cookies.
The passport library automatically adds a logout method onto the req object,
which makes it easy to log a user out of their account.
Once we’ve logged the user out, we simply redirect them back to the home page.
Writing the Templates
The last big thing we have to do is define our templates. The templates are
the HTML layer that gets presented to users.
Let’s get started!
Create a Layout
The first thing we’ll want to do is create a layout.jade template. By
default, our new express app is using the jade
templating language (check it out if you haven’t, it’s quite cool).
doctype html
htmlheadmeta(charset='utf-8')
meta(content='IE=edge',http-equiv='X-UA-Compatible')
meta(content='width=device-width, initial-scale=1',name='viewport')
title='Express-Stormpath(sample)|'+titlelink(href='/css/bootstrap.min.css',rel='stylesheet')
link(href='/css/style.css',rel='stylesheet')
<!--[ifltIE9]><script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
body.container.headerul.nav.nav-pills.pull-rightlia(href='/') Home
if user
lia(href='/dashboard') Dashbaord
lia(href='/logout') Logout
elselia(href='/login') Login
h3.text-muted Flask-Express
block body
script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js')
script(src='/js/bootstrap.min.js')
The main thing our fancy new layout template does is provide a basic HTML page
layout that all our other pages will use.
The line which reads block body will be overridden by our other templates.
The most important bit to take note of here is the nav menu:
123456789
if user
lia(href='/dashboard') Dashbaord
lia(href='/logout') Logout
elselia(href='/login') Login
block body
We’re using a simple conditional here to check to see whether or not a user is
logged in or not (if user), and changing the links the visitor sees
accordingly. This ensures that if a user is logged in, and on the homepage —
they won’t see a ‘Login’ button displayed in the navbar.
extends layout
block body
#welcome.jumbotronh1 Welcome to Stormpath-Express
p.lead.
<br/>
<br/>
Welcome to this gloriously simple <a href="https://github.com/stormpath/stormpath-express-sample">Stormpath</a>
sample app!
ulli First, take a look through this very basic site.
li.
Then, check out this project's source code
<a href="https://github.com/stormpath/stormpath-express-sample">on GitHub</a>.
li Lastly, integrate Stormpath into your own sites!
<br/>
<br/>
h2 What this Sample App Demonstrates
brp.
This simple app demonstrates how easy it is to register, login, and
securely authenticate users on your website using Stormpath.
p.
Aren't a Stormpath user yet?
<a href="https://stormpath.com">Go signup now!</a>
p.
<b>NOTE</b>:
This app will NOT work until you have gone through the bootstrapping
instructions found in this project's <code>README.md</code> file. For more
information, please follow the guide on this project's
<a href="https://github.com/stormpath/stormpath-express-sample">GitHub page</a>.
p.bigbuttona.bigbutton.btn.btn-lg.btn-danger(href='/register',role='button') Register
This is our home page template. All it does is render some static information
for users, so there isn’t much to go into here.
Since our layout.jade template is already handling our user-smart nav bar, we
don’t need to do anything special :)
The Registration Template
Place the following code into views/register.jade:
extends layout
block body
.register.row.col-lg-6.col-lg-offset-3form.bs-example.form-horizontal(method='post',action='')
fieldsetlegend Create a New Account
if error
.alert.alert-dismissable.alert-danger.register-failbutton.close(data-dismiss='alert',type='button') ×
p.
#{error}
p.
Registering for this site will create a new user account for you
via <a href="https://stormpath.com">Stormpath</a>, then log you in
automatically.
.alert.alert-dismissable.alert-infobutton.close(data-dismiss='alert',type='button') ×
strong NOTE:
Your password must be between 8 and 100 characters, and must
contain lowercase letters, uppercase letters, and numbers.
.form-grouplabel.col-lg-4.control-label(for='username') Email
.col-lg-4input#username.form-control(name='username',type='email',placeholder='Email',autofocus)
.form-grouplabel.col-lg-4.control-label(for='password') Password
.col-lg-4input#password.form-control(name='password',type='password',placeholder='Password')
.form-group.col-lg-10.col-lg-offset-4button.btn.btn-primary(type='submit') Register
h2 A Note About Stormpath Security
p.
In a real environment, you should <b>only deploy your application</b>
behind SSL / TLS to avoid having user credentials sent in plain text
over the network.
p.
Stormpath user creation is incredibly secure, is not susceptible to
any known vulnerabilities (MITM, hashing issues, replace attacks,
etc.), and provides you with a number of options to improve security
(including buil-in email verification, among other things). We will
not verify your account by email now, but this can be easily enabled.
p.last-p.
Stormpath can also be configured to allow for weaker (or force
stronger) passwords, so it can fit into any application workflow.
This page handles user registration.
Take a close look at the form — we’re specifying two fields for the user to
input: email and password. Take a look at the email input box, however:
Although we’re collecting a user’s email address here, we’re setting the HTML
name attribute to the value username. This is to make passport happy.
Passport expects username and password form elements, so that’s what we’ll
use (despite the fact that we’re signing a user with just email / password).
We’ll also render an error message to the user (if there is one). This will be
called if the registration fails for some reason, displaying a user-friendly
error message.
The Login Template
Start by putting the following code into views/login.jade:
extends layout
block body
.login.row.col-lg-6.col-lg-offset-3form.bs-example.form-horizontal(method='post',action='')
fieldsetlegend Login
if error
.alert.alert-dismissable.alert-danger.login-failbutton.close(type='button',data-dismiss='alert') ×
p.
#{error}
p.last-p.
Once you enter your credentials and hit the Login button below,
your credentials will be securely sent to
<a href="https://stormpath.com">Stormpath</a> and verified. If
your credentials are valid, you'll be logged in using a secure
session -- otherwise, you'll get a user friendly error message.
.form-grouplabel.col-lg-4.control-label(for='username') Email
.col-lg-4input#username.form-control(type='email',name='username',placeholder='Email',autofocus)
.form-grouplabel.col-lg-4.control-label(for='password') Password
.col-lg-4input#password.form-control(type='password',name='password',placeholder='Password')
.form-group.col-lg-10.col-lg-offset-4button.btn.btn-primary(type='submit') Login
The login template works almost exactly like the registration template we talked
about previously. Although we ask users to log in with an email and password,
we secretly name the email input field username to make passport happy.
Other than that, things work as you would expect if there is an error, we’ll
display a user-friendly error message.
The Dashboard Template
Put the following code into views/dashboard.jade:
123456789101112131415161718192021222324
extends layout
block body
.dashboard.row.col-lg-12.jumbotronh1 Dashboard
brbrp Welcome to your user dashboard!
p.
This page displays some of your user information using Jade
templates.
p.
If you click the Logout link in the navbar at the top of this page,
you'll be logged out of your account and redirected back to the main
page of this site.
p.
Your user account information is being securely stored using
passport sessions, and Stormpath as the authentication backend.
brbr
This is probably the simplest of all the templates — it just renders some
static content.
This page is only accessible to logged in users.
Static Assets
The last thing we need to do before we can run our awesome new project is drop
in our static assets. This mainly involves copying over
Twitter Bootstrap (I’m not a good designer, OK!).
You can run the following commands to download the necessary files locally (into
your public directory):
Now, open your browser and visit http://localhost:3000.
Assuming everything is working well, you should be able to register a new
account on the site, visit the dashboard, logout, and log back in again — with
no problems.
Firstly, if you made it to the bottom of this post: thanks! Hopefully you
enjoyed building this node app along with me!
With that said, in the future, we’re planning on expanding our Stormpath support
for both node.js and passport.js to make integration even simpler.
Among other things, we’d like to:
Make registering users a one liner (instead of requiring custom development
work).
Make asserting user permissions simple and effortless (making it easy to
handle user groups and permissions at a fine-grained level).
Make our passport.js middleware more magical by having it automatically patch
user data into templates for rendering.
Make our passport.js strategy support caching clusters (or either Redis or
Memcached) — this way you’ll be able to speed up user sessions quite a bit by
avoiding round-trips to the Stormpath REST API.
Got anything else you think would be cool to see added? Please
drop us a line! We’d love to hear from you :)
Over the past several weeks I’ve spent a ton of time hacking on the latest release of our brand new
Flask-Stormpath library.
Since the first release last month, I’ve received a ton of feedback — suggestions, ideas, and criticisms about what could be done better. It was
incredibly exciting!
With the latest release of the Flask-Stormpath library (0.2.0), the entire
library has changed — dramatically. It’s no longer a simple wrapper around
Stormpath, but a full blown user authentication system that goes out of its way
to automate and remove as much pain as possible from your web apps.
NOTE: Want to skip the fuss and just use it already? You can install it via
pip: $ pip install -U flask-stormpath
What’s New!
The latest edition of Flask-Stormpath includes several awesome new features:
Built-in views for handling registration, login, and logout
Built-in templates for registration and login pages. (They even look good!)
Fully integrated social login with Facebook and Google
Incredibly flexible library settings — you can fully control all aspects of the library just by modifying your Flask config: no coding needed!
What’s my favorite thing about the new release? Good question!
You can now add simple and secure user authentication to any Flask website in
as little as one line of code! Seriously. And you don’t even need a
database!
Here’s what our new built-in registration and login pages look like (without
customization, of course):
Social login is becoming a more and more popular form of web authentication —
it’s easy and convenient for users, which means more and more sites are
adopting it. When it comes to social login, there are essentially two providers
people care about: Facebook and Google.
At Stormpath, we recently built our own Facebook and
Google Login integration — and figured we’d share what we’ve learned recently
in this article.
This article will show you exactly how Facebook Login works, and how you can
easily plug it into your website.
NOTE: If you’re looking for a drop-dead easy way to do Facebook Login, you
might want to check out our brand newFacebook Login integration.
I think you’ll enjoy it.
High Level Overview
I’m sure you’ve used Facebook Login at least once or twice (if not, where do
you live? Under a rock!?).
The way Facebook Login works is theoretically quite simple:
A user visits your site and sees a big “Sign in with Facebook” button
somewhere.
A user clicks that button, and gets a little popup window asking the user to
accept an array of permissions.
The user clicks “Okay”, the popup closes, and the user is back on their
original page — but this time, they’re “logged in”.
This high-level flow is what’s known as OAuth 2.0.
OAuth is convenient for users because it means they don’t need to manually
create an account on each website they visit — they can use a single account
everywhere.
Adding Facebook Login to Your Site
Adding Facebook Login to a site is a fairly involved process. The simplest way
to do it is by using the
Facebook Javascript SDK.
The idea is that you add a button to your site which, when clicked, redirects
the user to Facebook to accept permissions, then back to your site when
everything is done.
The downside to using Facebook Login this way is that all authentication is done
via Javascript, so complex server-side applications require substantially more
work to function.
This guide will cover using the Javascript SDK only (as it is much simpler to
explain).
Getting Started: Create a Facebook App
The first thing you need to do in order to support Facebook Login on your site
is create a Facebook App.
To do this, you’ll want to head over to the
Facebook Developer Center and create or log
into your Facebook account.
Once you’ve logged in, you should be redirected back to the main Facebook
Developer page, where you’ll see a top navbar that looks like this:
To create a new Facebook App, click the “Apps” navbar tab, then click “Create a
New App”. You’ll now see a window where you can enter a “Display Name” (usually
the name of your website), and pick a “Category” (the category of your website).
You should see something that looks like this:
Enter these values, then click “Create App”. This will provision a new Facebook
App for your website, eventually allowing users to log into your website.
After you’ve created your new Facebook App, you’ll be redirected to your new App
dashboard! If all went well, you should now be at a page that looks like this:
This Dashboard page contains some useful stats (how many people have logged into
your website?) which you might find useful in the future — as well as your
Application’s ID and Secret.
The Application ID and Secret will be used later on.
Set Your Site URL
In order to support Facebook Login, you need to let Facebook know what URL(s)
your website will be running at. This way, Facebook can verify that a user is
actually being asked for permissions from the correct Facebook App.
To do this, click the “Settings” tab on the left nav menu, and click the “Add
Platform” button near the bottom of the page.
When prompted, select “Website” as your platform.
In the “Site URL” box that appears, you’ll want to enter your website URL.
For this example, I’m going to enter “http://localhost:8000” — as I’m going to
be testing this out on my local machine, on port 8000. You might want to set
this to something like: “http://mysite.com” if you’re testing this out on a
public domain.
NOTE: If you want to allow Facebook Login to work from multiple URLs (maybe
you use http://localhost:8000 for local development, and https://mysite.com
in production) you can simply click the “Add Platform” button again and enter
another URL.
Include the Facebook Javascript SDK in Your HTML
The next thing you need to do is include the Facebook Login button somewhere on
your website. You can do this by copy+pasting the following code into your HTML
code (this will render a Facebook Login button on your website).
<buttononclick="facebookLogin()">Facebook</button><script>functionfacebookLogin(){varFB=window.FB;varscopes='email,user_likes,public_profile';FB.login(function(response){if(response.status==='connected'){console.log('The user has logged in!');FB.api('/me',function(response){console.log('Good to see you, '+response.name+'.');});}},{scope:scopes});}window.fbAsyncInit=function(){FB.init({appId:'YOUR_FACBEOOK_APP_ID',cookie:true,xfbml:true,version:'v2.0'});};(function(d,s,id){varjs,fjs=d.getElementsByTagName(s)[0];if(d.getElementById(id)){return;}js=d.createElement(s);js.id=id;js.src="//connect.facebook.net/en_US/sdk.js";fjs.parentNode.insertBefore(js,fjs);}(document,'script','facebook-jssdk'));</script>
There are a few things to take notice of here:
You can choose what permissions you request from the user by modifying the
scopes variable (in this example it is set to request
'email,user_likes,public_profile). For more information on Facebook
permissions, visit this page: https://developers.facebook.com/docs/facebook-login/permissions
You need to replace YOUR_FACBEOOK_APP_ID with your App ID number from the
App Dashboard page you saw earlier.
When a user clicks the Facebook button, the facebookLogin() Javascript
function will run. This is what controls the pop-up, and post-login
behavior. In this case, after a user has logged in, we’re using the Facebook
API to grab the user’s information and print some debug information to the
developer console.
If you run this code in a simple HTML document, you’ll get a page that looks
like the following:
When you click the Facebook button, you should then see the standard permissions
pop-up — it looks like this:
Lastly, when you accept the permissions, you’ll notice that our Javascript
console.log messages worked!
Handle User Authentication
After including the Facebook Login button on your site, you can then handle user
authentication with Javascript.
On any web page where you want to enforce user authentication, you can do
something like the following:
1234567891011121314151617181920212223242526272829
<script>FB.getLoginStatus(function(response){if(response.status==='connected'){// If the user gets here, they're logged in.console.log('Logged in.');}else{// Redirect unauthenticated users to the login page.window.location.replace('/login');}});window.fbAsyncInit=function(){FB.init({appId:'YOUR_FACBEOOK_APP_ID',cookie:true,xfbml:true,version:'v2.0'});};(function(d,s,id){varjs,fjs=d.getElementsByTagName(s)[0];if(d.getElementById(id)){return;}js=d.createElement(s);js.id=id;js.src="//connect.facebook.net/en_US/sdk.js";fjs.parentNode.insertBefore(js,fjs);}(document,'script','facebook-jssdk'));</script>
The FB.getLoginStatus function provided by the Facebook Javascript SDK allows
you to easily check to see whether or not the current visitor is successfully
authenticated with Facebook (or not).
This code above will redirect any non-authenticated users back to the login page
(/login), and all other users will remain on the page.
NOTE: While this is great for simple apps, if you’re building something
where security is an issue, you should probably use the more complicated
server-side Facebook authentication flow. Stormpath makes this incredibly easy:
https://stormpath.com/blog/the-social-integration/
Conclusion
Facebook Login (via Javascript) isn’t that bad! It’s easy to implement and
style (you can change your button styles with CSS), but for more complex
authentication requirements, you should probably use the server-side flow.
Hopefully this short guide has been helpful! Have any questions? Shoot us an
email! support@stormpath.com
Ever since I wrote about the authentication problem in the Flask ecosystem
a few months back, I’ve been working hard to build a simple abstraction to
solve these issues.
When I launched the first version of Flask-Stormpath, I got a ton of
incredibly great feedback from the community, and learned a lot — namely,
people don’t want to worry about user authentication at all.
The Problem (a Recap) + A v.1 Solution
The “Authentication Problem” in the Flask ecosystem is this: since Flask has no
built-in ORM or tooling — almost every Flask developer ends up rolling their
own form of user authentication. There are currently no libraries which solve
all of the authentication problems. So, I built a first release of a Flask + Stormpath integration, which solved some big authentication problems in Flask:
Centralized (secure) user store.
No need to worry about hashing passwords or JOIN’ing database tables — that bit was handled automatically.
Easy to use user accounts.
Secure sessions.
After launch, I got a ton of excellent user feedback (thanks everyone!). After talking with lots of people, using the library myself, and writing a
Flask beginner tutorial, I realized that the first version of Flask-Stormpath was not really as good as I initially thought.
Learning and Planning
I realized that by even explaining how to do things like create registration, login, and logout views was a total waste of time — why should
developers have to do this stuff themselves?
So, I decided to revamp the initial Flask-Stormpath design and simplify all developer-facing code, such that:
Users could get registration, login, and logout working without writing any view code at all.
Users could control basic authentication features through app config variables (this way things are still flexible).
Users should be able to support social login with both Google and Facebook without doing any additional work.
Introducing the New Flask-Stormpath
I’m incredibly excited to announce the newest release of Flask-Stormpath —
it contains a huge number of improvements over the first release, and makes
handling user authentication in Flask apps incredibly simple.
In simple cases, registration, login, and logout are only a single line of code! No database required!
Here’s how this looks in practice:
1234567891011
fromosimportenvironfromflask.ext.stormpathimportStormpathManager# ...app.config['STORMPATH_API_KEY_ID']=environ.get('STORMPATH_API_KEY_ID')app.config['STORMPATH_API_KEY_SECRET']=environ.get('STORMPATH_API_KEY_SECRET')app.config['STORMPATH_APPLICATION']=environ.get('STORMPATH_APPLICATION')# This is where the magic happens.StormpathManager(app)
As you can see, we’re defining some settings, and initializing a
StormpathManager. What does this get you?
Firstly, you get a fully functional registration page out-of-the-box:
You also get a beautiful login page out-of-the-box (note the Google and Facebook buttons):
And lastly, you get logout functionality (if a user visits /logout they’ll be
logged out and redirected back to the site root).
There are currently three built-in views (along with templates and URL routes):
A registration view / template / route (bound to /register by default).
A login view / template / route (bound to /login by default).
A logout view / route (bound to /logout by default).
To make things even nicer, each of these views is 100% customizable — and
dynamically configure themselves based on your Flask settings.
Let’s take a deeper look!
Authentication Customization
Let’s say you’d like to modify the registration fields you accept when signing
up new users. Flask-Stormpath supports several user fields for registration:
email (required)
password (required)
given_name (first name)
surname (last name)
middle_name
username
So, let’s say you want to remove the first, middle, and last name fields from
the registration page — you could simply set the following configuration
variables:
Each of the available fields can be both ‘ENABLED’ and ‘REQUIRED’ to your
liking. This makes building dynamic registration / login pages incredibly easy.
But wait! There’s more!
You can also easily change the default routes around:
NOTE: The official template documentation has all the information you
could ever need / want on how to build you own registration / login templates
(it’s super easy!).
Furthermore, handling social login is incredibly simple. You can easily enable
or disable social login support for both Facebook and Google by modifying
configuration variables alone:
The new Flask-Stormpath design is based around abstraction: the main idea is
to make authentication as simple and painless as humanly possible. If you’re
building a Flask app, you no longer have to worry about storing / securing user
data at all — it’s completely handled, scaled, and secured.
From this point forward, I’ll be slowly adding more convenience features to the
Flask-Stormpath integration to handle other things as well:
Email verification for new users.
API key authentication (an awesome new feature for securing REST APIs).
Password reset.
Distributed caching support (redis, memcache, etc.).
I’m extremely excited about the new Flask-Stormpath, and hope you are too!
Furthermore, if you aren’t already a Stormpath user — you should go
create an account right now! It’s free for up to 100,000 API requests
per month! That means most small to medium sized projects can use Stormpath
for zero cost, ever.
And as always, I’d love to hear from you! Please hit me up (I’m
randall@stormpath.com).
While Stormpath is great for storing user accounts — did you know you can
also store custom data for each user? Stormpath’s custom data makes it
possible to store rich profile data and other information on a user account.
enrich is a simple Node.js command line tool which analyzes your Stormpath
user accounts, finds a plethora of information on each user (by email
address), then stores this data in your user account’s custom data store.
enrich makes it incredibly easy to build rich user profiles automatically!
Let’s say you’ve got a Stormpath Application with several user accounts, one of
which has an email address, r@rdegges.com.
When you run enrich, it’ll go through each user account, and do several things:
Grab the user’s email address.
Use FullContact’s API service to search for publicly available information
on this user.
Store whatever information is available in your Stormpath user account’s
custom data store — so you can access it later.
FullContact is an extremely useful API service which scours the web for
information about users by email address — it will scrape information from
Facebook, Twitter, Google, etc., and return a single record with all of the
user’s information.
When I run enrich on my personal account, I get the following custom data
stored in my user account:
{"contactInfo":{"familyName":"Degges","fullName":"Randall Degges","givenName":"Randall","websites":[{"url":"http://rdegges.com"},{"url":"http://www.theherokuhackersguide.com/"},{"url":"http://www.pycall.org/"},{"url":"http://rdegges.com/"},{"url":"http://www.telephonyresearch.com/"}]},"demographics":{[81/208]"gender":"Male","locationGeneral":"California, USA"},"organizations":[{"current":false,"isPrimary":true,"name":"Telephony Research","startDate":"2012","title":"Chief Hacker"},{"current":true,"isPrimary":true,"name":"Stormpath","startDate":"2014-02","title":"Developer Evangelist"},{"current":false,"endDate":"2009","isPrimary":false,"name":"Fonality","startDate":"2008","title":"Programmer"},{"current":false,"endDate":"2012","isPrimary":false,"name":"BTS","startDate":"2009","title":"Lead Developer"}],"photos":[[45/208]{"isPrimary":true,"type":"facebook","typeId":"facebook","typeName":"Facebook","url":"https://d2ojpxxtu63wzl.cloudfront.net/static/aaf383528d6026df23bb342bbde8b295_f44fb7ef5c407df39029ef3160f4c075a0f82acfa00d30028b396922158cdc01"},{"isPrimary":false,"type":"foursquare","typeId":"foursquare","typeName":"Foursquare","url":"https://d2ojpxxtu63wzl.cloudfront.net/static/0cb868fc5a274771605c0e0d7f955ee6_2c5fa7a99f9d322c6476ee374a22467000e88730a06aacc95e328c4e1f8071f2"},{"isPrimary":false,"type":"googleplus","typeId":"googleplus","typeName":"Google Plus","url":"https://d2ojpxxtu63wzl.cloudfront.net/static/9c9350196801eb617b70f00b29a78b1c_91431537e46e579dcfbcfaf069196dd1817c82a34ef4481dd06e5bdc6e630601"},{"isPrimary":false,"type":"twitter","typeId":"twitter","typeName":"Twitter","url":"https://d2ojpxxtu63wzl.cloudfront.net/static/d0f046119d0f5438924c8442eadb6f1b_2fc73d27aa217ccfb1d969847d8d53d0687986c742a86dd6173cf689ffa749c9"},{"isPrimary":false,"photoBytesMD5":"e0139f33ef023149308b26076b240c9a","type":"gravatar","typeId":"gravatar","typeName":"Gravatar","url":"https://d2ojpxxtu63wzl.cloudfront.net/static/8058dbaadafd9ea2859c84c5ecb275d7_49977cacdcd42944e609608797cf5548ba3f8b66881f97399c143212e1809314"},{"isPrimary":false,"type":"linkedin","typeId":"linkedin","typeName":"LinkedIn","url":"https://d2ojpxxtu63wzl.cloudfront.net/static/d6ff74c0e6d4e4c48d2daf2be82fd7b8_452404fa403cf2cc1b90611542d39197f8ef7d51b02ec8e8bba3f46142535132"}],"socialProfiles":[{"bio":"I'm just a happy programmer that likes to hack stuff.","id":"75427646","type":"foursquare","typeId":"foursquare","typeName":"Foursquare","url":"https://www.foursquare.com/user/75427646"},{"id":"53099533","type":"gravatar","typeId":"gravatar","typeName":"Gravatar","url":"http://gravatar.com/rdegges","username":"rdegges"},{"bio":"I'm the Chief Hacker @ Telephony Research, where I build telephony tools for developers using cool technologies.","followers":0,"following":0,"id":"105723327194710521939","type":"googleplus","typeId":"googleplus","typeName":"Google Plus","url":"https://plus.google.com/105723327194710521939"},{"id":"85568398087900609","type":"klout","typeId":"klout","typeName":"Klout","url":"http://www.klout.com/user/rdegges","username":"rdegges"},{"bio":"I'm just a happy programmer that likes to hack stuff.","followers":1623,"following":1158,"id":"28896389","type":"twitter","typeId":"twitter","typeName":"Twitter","url":"http://www.twitter.com/rdegges","username":"rdegges"},{"bio":"Developer Evangelist at Stormpath","type":"linkedin","typeId":"linkedin","typeName":"LinkedIn","url":"https://www.linkedin.com/pub/randall-degges/8b/34a/132"},{"type":"flickr","typeId":"flickr","typeName":"Flickr","url":"http://www.flickr.com/photos/rdegges","username":"rdegges"},{"bio":"I'm a happy programmer who enjoys using python, django, c, asterisk, freeswitch, opensips, and telephony to build fun, efficient, and awesome apps.","type":"aboutme","typeId":"aboutme","typeName":"About.me","url":"http://about.me/rdegges"},{"followers":124,"following":124,"id":"6717855","type":"facebook","typeId":"facebook","typeName":"Facebook","url":"https://www.facebook.com/rdegges","username":"rdegges"}]}
As you can see, enrich was able to grab a LOT of information about me, based
solely on my email address!
Enriched Data
By default, enrich will attempt to grab several data points
for each user you have:
photos
contactInfo
organizations
demographics
socialProfiles
Depending on the what’s publicly available, some of these sections may not be
available. When I ran a test on our Stormpath employees, I was able to find a
lot of information on just about every person here!
Why Enrich Your Users?
Enrich allows you to customize your user experience very easily. Let’s say I wanted to build a very simple SaaS application — using enrich
I’d be able to:
Register a new user with only an email address and password.
Automatically find this user’s avatar, and use it in my interface to help give
my dashboard a more personalized feel.
Automatically find this user’s first and last name to greet them (“Welcome
back, Randall!”).
Integrate deographic information like age, gender, and location into my analytics.
Figure out what organization this user is associated with (maybe they’re the
CEO of a huge company, and you should email them directly!).
After you’ve created your accounts, and have your API keys, all you have to do
to configure enrich is run:
1
$ enrich --configure
And you will be prompted to enter your credentials.
Once that’s done, just run:
1
$ stormpath-enrich
And your user accounts will be automatically enriched!
NOTE: For best results, I recommend running enrich on a cron job
periodically, this way you’ll continuously update your user accounts with the
latest available information.
Thoughts, Feedback?
If you’ve got any thoughts or feedback, I’d love to hear it! Please leave a
comment below, or drop me a line.
Today, I’m ecstatic to announce the 0.2.0 release of our Node.js SDK, complete with updated docs and a host of fixes and new functionality. When we first released the 0.1 version in March, the fast adoption surprised us. Since then, we’ve been working hard to incorporate all your feedback (thanks!), fill out the features, and make it awesome for Node users. In this article, I’ll walk through the major improvements we’ve made in this release. Please check out the new version and please share your feedback!
Social Login
You can now use the Node.js SDK to login your users with Facebook or Google. Stormpath Social Login retrieves user profiles from social networks and converts them to full Stormpath accounts, complete with functionality like passwords for your app and custom user profile data. Take a look at our Social Integrations guide for more information on how it works.
Full Custom Data Support
We finished implementing custom data support in Node.js. It’s the easiest way to add ad-hoc data to your Accounts and Groups. No database work and it’s super simple to implement:
This release gives Node.js devs more sophisticated control over setting, querying, and updating the mappings between your account stores in Stormpath and your application.
We’ve expanded caching implementations to include network-accessible stores like Redis and Memcached. Caching improves performance by reducing round trip calls to Stormpath.
Caching is incredibly easy to implement for Node apps backed by Stormpath – without code changes. Simply provide an additional parameter when you create a Stormpath Client instance.
Iterator Methods on Collection Resources
Collection resources in Stormpath are pre-defined “parent” resources that contain “child” instance resources. This release brings new methods to make it easy to iterate over those collection resources. For instance, it’s now simple to produce an array of your Stormpath Application names:
function pluckAppName(application, cb){
cb(null, application.name);
}
applications.map(pluckAppName, function(err, results){
// results is now an array of names for each application
});
Updated Docs
Last but not least, we’ve massively updated the Node.js API docs. There are all-new sections, clearer explanations, revamped code samples, and more detail all around.
Stay tuned for two more major features coming soon to Stormpath and the Node SDK! And as always, leave us your feedback on today’s release in the comments, on support, or @goStormpath.
Over the past couple of months, I’ve been getting more involved in the
Node.js community: writing more Node code, building apps, and getting familiar with the ecosystem.
As a developer, it’s really interesting getting familiar with a new language /
framework / community. There’s a lot to learn: the language, ecosystem, tools, best practices and idiosyncrasies.
When it comes to mastering these, there’s really no substitute for
experience and time. And, while I’m not exactly “at home” in Node yet, I’ve been reading through
various resources trying to educate myself more, and reach that nirvana-esque
state of development where everything comes naturally.
As I’ve been going along I’ve been putting a small reading list together, which
I thought I’d share. Here’s my Node reading list!
Books
I read a lot of tech books. While some people learn best through hearing or
trying something, I tend to learn best through reading.
With that in mind, here are my favorite Node books.
First up is Douglas Crockford’s classic book, Javascript: The Good Parts.
It’s widely considered to be the best text on modern Javascript, as it covers
exclusively the parts of the language that you should be actively using.
Javascript is a big language, and it has a lot of quirks. This book teaches you
in a very clear and concise way exactly what language features you should be
using, and why.
I’ve read this book several times over the past few years, but after getting
more involved with Node I’ve come to realize how critical it is for any
Javascript developer.
When you’re spending a lot of time writing server-side Javascript, you’ll be a
lot better off armed with the knowledge from this book. There are a lot of
language “gotchas” which make knowing the language very well a necessity for
good Node development.
The next book I’d recommend to new Node developers is The Node Beginner Book.
It’s a very simple and straightforward introduction to Node for developers
who’ve primarily used Javascript on the front end, and never really messed with
it as a backend language before.
What I really enjoyed about this book is it’s tone: it’s leisurely, enjoyable,
and incredibly useful for new Node developers. It covers all Node basics, and
gives you a good feel for basic usage. It’s definitely worth
buying and reading over a weekend.
Sites
Another great way to get a good “feel” for a new language / framework is to
keep up with popular sites.
How to Node is a popular Node community blog which publishes articles on a
variety of Node related topics:
How to do something in Node.
Common gotchas.
What something is.
Why something works the way it does.
Introduction to a specific tool / concept.
I’ve found many of the articles extremely simple and useful — you might too!
NPM Awesome is a really great blog written by Alex Gorbatchev in which he
reviews various npm modules.
I find NPM Awesome to be a great resource for learning what new Node modules
are coming out, what’s good about them, what’s bad about them, and more
generally: what stuff I should look into using.
It’s quickly become one of my favorite resources for discovering cool new stuff
on npm and finding ways to sneak it into my projects >:)
Mailing Lists
There’s really only one mailing list you should subscribe to, and that’s node
weekly. It’s a weekly email list that does an amazing job of finding
relevant npm modules, node articles, and generally interesting node information.
It’s 100% worth signing up for, no question.
[Disclaimer: Stormpath has sponsored node weekly in the past. Because it is awesome.]
Podcasts
I usually do a lot of driving in the Bay Area (going from event-to-event), and
have gotten in the habit of listening to a few podcasts to make the commuting
more bearable.
nodeup is the only real Node podcast I’m familiar with — but it’s pretty
great. The show covers:
Node core development.
Node modules.
Chatting with various Node developers.
Thoughts on various programming techniques / strategies.
Overall, I’d say it’s a really great podcast (particularly if you’re interested
in learning more about Node tools and practices). The only downside (to me)
is that episodes are roughly an hour each, which is longer than I want to be in the car.
It’s very casual, however, and easy to listen to.
Exercises
Although I don’t normally do exercises, I’ve spent some time playing around with
various hands-on Node resources.
node school is without a doubt, my favorite hands-on Node resource. It’s an
interactive command-line-driven lesson / tutorial in which you’re given some
instruction, then sent off to write your own Node programs which it’ll then
verify for correctness.
Not only are the exercises incredibly fun, but also very well written and
sufficiently challenging.
If you’re going to give node school a try, I suggest you block off several
hours of time to sit down and go through the exercises without any distraction.
Wrap Up
I hope this list has been of some help — if you have any other recommendations, please leave a comment below!
And if you’re interested in easy user management for your Node app, please checkout Stormpath or jump right in with our Node.js 7-Minute Tutorial .
It’s no secret that if you’re building an Express web app, adding in user
authentication is quite difficult. If you google “Express Authentication”,
you’ll be directed to one of two tools:
While both Passport and everyauth are really great tools, as a relatively new
Node developer, I had a difficult time figuring out how to actually
use them in a real application.
I honestly don’t want to setup / configure my own session management stuff, or
worry about creating my own login / registration views securely.
After a lot of discussion internally at Stormpath, we decided it would be
awesome to build a really simple, powerful, and elegant authentication system
for Express.
Which brings me to…
express-stormpath
For the past week, I’ve been working on building an authentication
library that would abstract away all the details, and make adding user
authentication to Express apps drop-dead easy.
NOTE: If you aren’t a Stormpath user already, Stormpath is an API service
that makes managing users simple. It’s completely free for small apps.
express-stormpath allows you to painlessly add complete user authentication
(including registration, login, and logout) into your Express apps in just a
few lines of code.
The secretKey must be a long random string (used to secure sessions), while
the other fields contain your Stormpath account settings. For more information
on setting up a Stormpath account, you can check out the Setup section of
our docs.
The above code sample is a fully functional Express app which has three
pre-configured routes:
A registration route (/register), which looks like this:
A login route (/login), which looks like this:
And a logout route (/logout) which logs users out of their account.
Out of the box you get user registration, login, and logout!
Just to demonstrate how easy it actually is, here’s a 90 second screencast I
made in which I’ll create a brand new Express app from scratch with full user
registration and login!
Customization
With express-stormpath, you can also customize essentially every part of the
library very easily.
Let’s say, for instance, that after a user creates a new account or logs in,
you’d like to redirect them to a dashboard page (/dashboard), you can easily
do this by specifying the redirectUrl setting when initializing the
middleware, like so:
Or, what if you want to change the view code to add in your own styles / etc?
It’s incredibly simple! I wrote a guide which explains how to do it in
explicit detail.
You can easily change / remove / modify any part of the express-stormpath
library by modifying middleware settings — it really is that simple.
Exploring express-stormpath
If you’d like to give express-stormpath a try, here are some code samples
which illustrate how to use the library in a bit more depth.
Let’s say you want to write a route which requires a user to be logged in.
You can do this easily by using the stormpath.loginRequired tooling:
123
app.get('/dashboard',stormpath.loginRequired,function(req,res){res.send('If you can see this page, you must be logged into your account!');});
When a user visits /dashboard, we’ll automatically check to ensure the user is
logged in before allowing them to continue. If the user isn’t logged in,
they’ll be redirected to /login?next=%2Fdashboard, so once they log into their
account, they’ll be immediately sent back to the dashboard page!
Furthermore, you can also require a user to be a member of one or more groups in
order to access a route. For instance, if you’d like to build an admin panel
that’s exclusively available to users in the ‘admins’ group, you could do:
123
app.get('/admin',stormpath.groupsRequired(['admins']),function(req,res){res.send('You are an admin!');});
To assert that a user is a member of multiple groups, you can simply list
multiple groups, ex:
123
app.get('/admin',stormpath.groupsRequired(['admins, developers']),function(req,res){res.send('You are an admin and developer!');});
You can also assert that a user is a member of one or more groups by passing an
optional flag:
123
app.get('/hmm',stormpath.groupsRequired(['admins, developers','dudes'],false),function(req,res){res.send('You are either an admin, developer, dude, or some combination of them all!');});
In your route code, you can also access the current user object by calling
res.locals.user like so:
It’s no big secret: if you’re not using SaaS products to build your next great app, you’re wasting a lot of time.
Seasoned web developers have learned to solve common (i.e. annoying) problems with packaged solutions. If you’re really badass, your latest app is a symphony of amazing services, not a monolithic codebase that suffers from Not Invented Here.
But I’m gonna put money on this: you’re still building your login and registration forms from scratch and maintaining your own user database.
Why do we build login from scratch?
I have a few hypotheses on this, but one always seems to be true: user systems are the first thing we do after we master the Todo demo app. It’s fun, it’s a feature and we feel like we’ve accomplished something. Eventually we learn that there are a lot of things you can get wrong:
Storing passwords in a database, in plaintext
Giving users a cookie session that never expires
Building a crappy (or nonexistent!) password reset flow, to the ire of the support team
Storing the entire user object in application memory in order to improve page times
I could go on, but you already know. We commit these sins in the spirit of Ship It!.
Sometimes we use a framework like Rails, Express or Django and avoid most of these pitfalls by using their configurable user components. But we’re trying to get to App Nirvana, we want fewer concrete dependencies, less configuration, fewer resources to provision.
Login as a Service
What if you could send your user to a magical place, where they prove their identity and return to you authenticated?
Announcing Hosted Login – our latest offering from Stormpath!
With Hosted Login you simply redirect the user to a Stormpath-hosted login page, powered by our ID Site service. We handle all the authentication and send users back to your application with an Identity Assertion. This assertion contains all the information you need to get on with your business logic.
And the best part? Very minimal contact with your backend application. In fact, just two lines of code (using our SDKs):
One to create the URL which takes the user to the hosted login screen
One that parses the identity assertion when they return to your application
And with that.. your entire user system is now completely service-oriented. No more framework mashing, no more resource provisioning. Oh, did we mention that’s beautiful as well? That’s right: if you don’t want to do any frontend work either, you can just use our default screens:
What problems does it solve?
Hosted Login solves a lot of the problems that are sacrificed in the name of Ship It, plus a few you may not have thought of:
Security best practices (HTTPS for all components, enterprise grade security on our backend)
Complete flows for registration, verification, login, and password reset
Social login for Google and Facebook
No provisioning or securing your database
Customization
While we provide default screens for hosted login, you can fully customize your user experience. Just create a Github repository for your ID Site assets and give us the Github URL! We’ll import the files into our CDN for fast access and serve your custom login pages instead of our default.
To customize your hosted login pages, you’ll want to use Stormpath.js, a small library that I’ve written just for this purpose. It gives you easy access to the API for ID Site and at ~5k minified it won’t break the bank.
I’ve built many Express applications recently, and it’s reminded me of the
pains of building password reset functionality since there are many Express
tools for handling it. Building password reset is a drag for most developers,
every application needs it, and getting it wrong can have a major impact on
your application.
This post is an effort to reduce the pain of building password reset for other
node developers by first describing the systems you’re going to need and then
offering a recommended workflow for password reset.
Systems Needed for Password Reset
For starters, Express requires you to build out a proper user system. Your
first reaction would be to use Passport, but you’ll quickly find that
Passport does not store accounts — you still have to do that yourself.
Passport is good for adding authentication strategies (like
Facebook vs username/password) if you already have a user management system
in place. So, get coding.
With a user system in place, you start to build password reset. First, you
need several additional routes for the pages in the password reset flow, and
to include input validation and CSRF protection for your forms.
Then you’re going to need an email component to send the user their secure URLs
and tokens. If you don’t already have email built into your application, you
might want to use an email service like Sendgrid or Mailgun. Next,
email templates for each part of the reset process.
Almost there. You now need to get those reset tokens working. First, you need
the logic to create unique tokens for each reset attempt and expire them within
a certain time frame and on first use. That will include an additional table
to store the tokens and their expiration metadata. Then build the logic in
your code to authenticate and verify those tokens before a reset can be
completed.
All in all, it’s dozens of hours of work (possibly more) you would probably
rather spend on core application business logic.
And while it’s not rocket science, hand-rolled password reset workflows can be
error prone and those errors directly translate to vulnerabilities in your
application — user accounts can be hijacked. Since password reset is not core
to most applications, these types of vulnerabilities are often not discovered
until they actually get exploited.
So, let’s talk about how to build it the right way.
Password Reset Workflows – The Right Way
Over the years I’ve used numerous password reset systems, and there is really
only one good way to handle password reset functionality in your web
applications.
Here’s how we recommend you do it:
On your login page, there should be an obvious “Forgot your password?”
link. Otherwise you’ll confuse users and increase either support tickets or
abandonment.
When a user gets to your password reset page, and enter their email address.
You may want to ask for a second factor to identify the user at this stage
or a later stage.
After the user has entered their email address, send them an email with a
link to the password reset page on your site. This link should contain a
unique password reset token that expires after a certain amount of time
and one first use. If your token isn’t unique, doesn’t expire — you’ve
got a very real vulnerability on your hands.
After you’ve sent the user an email, give them a message telling them what
to do! Tell the user you sent them an email, and tell them to check their
inbox. If you immediately redirect them somewhere else, they’ll be confused!
After the user clicks the link in their email, they should be brought to a
page on your site that prompts them to enter a new password. Ensure you
make the user enter their new password twice so they don’t forget what they
just typed. Make sure you validate their token before proceeding! If the
token isn’t valid, you should display an error message and instructions on
how to proceed.
Once the user has reset their password, give them a confirmation message to
eliminate confusion. “Your password has been reset” is typically good
enough.
Lastly, ensure you send the user an email once their password has been
changed letting them know what happened. This will ensure the user knows
what they did, and is a great auditing tool in the future. It’s also an
easy alert in the event the user didn’t initiate the reset themselves.
If any of these steps is missing, you may confuse your users and open yourself
up to security vulnerabilities.
Take the token, for instance. If this token isn’t validated — that means
anyone can reset one of your user’s passwords — and that’ isn’t a good thing.
If your tokens don’t expire after a short period of time (usually 24 hours),
then you’ve got an issue. What if this user’s email gets compromised in the
near future? What if the token can be easily guessed?
And lastly, if your token isn’t actually unique — you’ll be in for some
embarrassing work meetings. For instance, I’ve noticed that many sites set the
password reset token to a guessable number! For instance, if you use an
incrementing integer value (1, 2, 3, …), it’s quite easy for attackers to
guess at these numbers until they find a valid one.
NOTE: It’s also worth mentioning explicitly that you should NEVER send
your users an email containing their password. This means that you’re more
than likely storing your passwords in plain text (an awful idea), and exposes
users to additional risk: what happens if someone looks over their shoulder as
they read their email and sees their password? That doesn’t just happen in
movies.
Stormpath’s Password Reset Workflow
The Stormpath API has always handle password reset for developers so you
don’t have to go through this pain. And we have a great ExpressJS integration.
And I just added password reset to it, so you don’t have to!
If you aren’t familiar with Stormpath, we’re API service you can use to deploy
complete user management in your application — login, user profiles, password
reset, Facebook integration, etc. And it’s all under the hood, your end-users
never know we exist.
Our popular express-stormpath library fully supports password reset. You
can instantly add password reset into your ExpressJS web applications with a
single line of configuration information:
After enabling the password reset functionality with the Stormpath middleware,
a magical link will appear on your login page that allows users to start the
password reset process.
Below are some screenshots that demonstrate what users will see with the
baked-in views (100% customizable, of course):
If you’d like to check it out, give some feedback, or point out ways to improve
the new Express integration, please take a look at the new
password reset documentation and let me know what you think.
Single Sign-On (SSO) has become an over-loaded term for many developers. It’s used, sometimes inaccurately, to refer to any tool that simplifies login for the end-user. But SSO has a very specific technical definition, and the confusion increasingly makes it difficult for developers to find the right tool for the job.
In most cases, what a developer is really looking for is one (or a combination) of three different tools: Centralized Authentication, Social Login (i.e. Facebook Login), or actual Single Sign-on.
Social Login is pretty well defined at this point, and most developers know what it is— the user logs into your application by clicking a facebook button and using their Facebook credentials (usually through a custom Facebook OAuth flow). You can learn all about it in our Facebook Login Guide.
Less clear and often more misunderstood is the difference between Single Sign-On and Centralized Authentication. At Stormpath we see this confusion often and wrote this article to help developers find the right solution for their application.
Single Sign-On
With single sign-on (SSO), users are authenticated only once, regardless of how many other applications they attempt to access after the initial login. In general, this is achieved when the SSO Identity Provider (IDP) sends the target applications an assertion that the user has been authenticated and should be trusted by that application.
For example, say a user logs on to Application 1, then decides to access Application 2. Typically, Application 2 would require another username and password for authentication. But in an SSO environment, Application 2 simply determines whether it can authenticate the user based on information the SSO IDP provides. The assertions are typically based on a common protocol like SAML, OpenID Connect, or JWT.
SSO solves two major problems for users:
They don’t need to enter authentication information multiple times
…or remember multiple sets of login credentials
It also requires a user repository in order to authenticate a user for the first time. Typical user repositories include Active Directory, LDAP, a custom database, or Stormpath. In turn, these same repositories are often centralized authentication and user management systems.
On its own, SSO is a poor solution for sharing user data across applications, as SSO generally expects the application (or “Service Provider” in SSO speak) to maintain its own user management system. More specifically, when an SSO provider sends an authentication assertion to an application, it still needs to create or look up the user in the app’s own local repository. Even though the application can trust that the user is authenticated.
Centralized Authentication
With centralized authentication, the authentication process is different. Once a user has logged into Application 1, logging into App 2 doesn’t feel automatic. Even though the required credentials are identical, the user would still need to enter her authentication information again.
Like SSO, Centralized authentication solves two problems, but the problems are different:
Users don’t need to remember multiple sets of authentication credentials
The applications they are logging into can share user data.
Typically, centralized authentication solutions completely offload user management from an application. They provide powerful APIs or query languages to connect the user system to one or many applications. Moreover, centralized authentication is often the first step toward a true SSO environment.
SSO vs Centralized Authentication? Why not both?!
So, should you use SSO or Centralized Authentication in your application? Of course the answer is: it depends.
If you’re trying to create a single user repository that all your applications can share, you will want a centralized authentication and user management system.
If, on the other hand, you have a variety of applications with their own built-in user data and management, but you want to create a seamless user experience, you’ll be best served by SSO (if those apps support it).
However, SSO and Centralized Authentication are not direct competitors. In fact, many developers implement both to give customers a seamless user experience across applications or web properties. At the same time, an SSO/Centralized Authentication combo allows development teams to share user infrastructure across applications, so they aren’t reinventing the identity system with each new application.
Stormpath combines both SSO and Centralized Authentication in one clean and elegant user management system. With an elegant API, powerful SDKs, and easy to use framework integrations, your applications have full access to user and group data .
In addition, we now offer SSO across your custom applications with little to no coding on your end through our new ID Site feature, so you can offer customers a seamless user experience.
If you are a Java developer, then you are undoubtedly familiar with frameworks such as Spring, Play!, and Struts. While all three provide everything a web developer wants, I decided to write a RESTful web application using the Jersey framework. This sample app uses Java + Jersey on the back-end and Angular JS on the front-end.
Jersey annotation service makes it easy to do routing, injection, and other functions important to a RESTful web application. My goal was to demonstrate the use of the Stormpath Java SDK for user management and the protection of a REST endpoint using API Keys and Oauth Tokens, all while relying on Jersey.
You can check out the Stormpath Jersey sample app in github, and follow along here for the implementation details and concepts I found most important while building this application. I will explain Stormpath SDK calls, Jersey annotations, and the general flow of the application, so it the codebase is easy to decipher.
Let’s code!
Login
Stormpath provides username/password authentication in three lines of Java SDK method calls. That makes it very simple to launch a basic login form, securely.
As soon as a user enters their credentials and clicks the “Sign In” button, an AJAX request is made to the /login endpoint. Let’s take a look at the server side login code:
@Path("/login")
public class Login {
@Context
private HttpServletResponse servletResponse;
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void getDashboard(UserCredentials userCredentials)
throws Exception {
Application application = StormpathUtils.myClient.getResource(
StormpathUtils.applicationHref, Application.class);
AuthenticationRequest request = new UsernamePasswordRequest(
userCredentials.getUsername(), userCredentials.getPassword());
Account authenticated;
//Try to authenticate the account
try {
authenticated = application.authenticateAccount(request).getAccount();
} catch (ResourceException e) {
System.out.println("Failed to authenticate user");
servletResponse.sendError(401);
return;
}
Cookie myCookie = new Cookie("accountHref", authenticated.getHref());
myCookie.setMaxAge(60 * 60);
myCookie.setPath("/");
myCookie.setHttpOnly(true);
servletResponse.addCookie(myCookie);
}
}
Here we see three examples of Jersey’s annotation feature. The @Path annotation acts as our router. The @Context annotation injects the HTTP Request object into our class. Finally, the @POST specifies the CRUD operation.
User authentication is done by first creating an Application object, creating an AuthenticationRequest object, and finally calling application.authenticationAccount(request) to ask Stormpath to authenticate this account.
Create Account
Creating an account is just as simple as logging in to the service:
@Path("/makeStormpathAccount")
public class StormpathAccount {
@POST
public void createAccount(UserAccount userAccount) throws Exception {
Application application = StormpathUtils.myClient.getResource(
StormpathUtils.applicationHref, Application.class);
Account account = StormpathUtils.myClient.instantiate(Account.class);
//Set account info and create the account
account.setGivenName(userAccount.getFirstName());
account.setSurname(userAccount.getLastName());
account.setUsername(userAccount.getUserName());
account.setEmail(userAccount.getEmail());
account.setPassword(userAccount.getPassword());
application.createAccount(account);
}
}
All we had to do here, was create an Application and an Account, set the Account attributes, and call createAccount.
Generating an API Key ID/Secret
Once a user logs in, they will be given API Key credentials. In this application, generation of the Keys is a simple AJAX call to /getApiKey:
@Path("/getApiKey")
public class Keys {
@Context
private HttpServletRequest servletRequest;
@Context
private HttpServletResponse servletResponse;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Map getApiKey(@CookieParam("accountHref") String accountHref) throws Exception {
Account account = StormpathUtils.myClient.getResource(accountHref,
Account.class);
ApiKeyList apiKeyList = account.getApiKeys();
boolean hasApiKey = false;
String apiKeyId = "";
String apiSecret = "";
//If account already has an API Key
for(Iterator<ApiKey> iter = apiKeyList.iterator(); iter.hasNext();) {
hasApiKey = true;
ApiKey element = iter.next();
apiKeyId = element.getId();
apiSecret = element.getSecret();
}
//If account doesn't have an API Key, generate one
if(hasApiKey == false) {
ApiKey newApiKey = account.createApiKey();
apiKeyId = newApiKey.getId();
apiSecret = newApiKey.getSecret();
}
//Get the username of the account
String username = account.getUsername();
//Make a JSON object with the key and secret to send back to the client
Map<String, String> response = new HashMap<>();
response.put("api_key", apiKeyId);
response.put("api_secret", apiSecret);
response.put("username", username);
return response;
}
}
We use Jersey’s @CookieParam annotation to grab the account Href from the Cookie that was created at login. We create an account, and an ApiKeyList object. We then check if this account already has an API Key. If so, our job is to simply request it from Stormpath; if not, we tell Stormpath to make a new one for this account and return this back to the client. By Base64 encoding the API Key:Secret pair, a developer can now target our endpoint using Basic authentication:
Using a Jersey Filter
A cool feature of the Jersey framework is its Request filter. By implementing ContainerRequestFilter we can intercept an HTTP request even before it gets to our endpoint. To demonstrate, I added an additional level of security around API Key generation. Before a user is allowed to target the /getApiKey endpoint they must pass through the Jersey request filter, which will check if the client is actually logged in (a.k.a has a valid session in the form of a cookie).
If a client is trying to get an API Key without being logged in, they will get a 403 before even reaching the actual endpoint.
Exchanging your API Keys for an Oauth Token
Want even more security? How about trading your API Key for an Oauth Token? Using Oauth also brings the functionality of scope, which we can use to allow users to get weather from specified cities.
Let’s take a look at the code:
@Path("/oauthToken")
public class OauthToken {
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String getToken(@Context HttpHeaders httpHeaders,
@Context HttpServletRequest myRequest,
@Context final HttpServletResponse servletResponse,
@FormParam("grant_type") String grantType,
@FormParam("scope") String scope) throws Exception {
/*Jersey's request.getParameter() always returns null, so we have to
reconstruct the entire request ourselves in order to keep data
See: https://java.net/jira/browse/JERSEY-766
*/
Map<String, String[]> headers = new HashMap<String, String[]>();
for(String httpHeaderName : httpHeaders.getRequestHeaders().keySet()) {
//newBuilder.header(String, String[]);
List<String> values = httpHeaders.getRequestHeader(httpHeaderName);
String[] valueArray = new String[values.size()];
httpHeaders.getRequestHeader(httpHeaderName).toArray(valueArray);
headers.put(httpHeaderName, valueArray);
}
Map<String, String[]> body = new HashMap<String, String[]>();
String[] grantTypeArray = {grantType};
String[] scopeArray = {scope};
body.put("grant_type", grantTypeArray );
body.put("scope", scopeArray);
HttpRequest request = HttpRequests.method(HttpMethod.POST).headers(
headers).parameters(body).build();
Application application = StormpathUtils.myClient.getResource(
StormpathUtils.applicationHref, Application.class);
//Build a scope factory
ScopeFactory scopeFactory = new ScopeFactory(){
public Set createScope(AuthenticationResult result,
Set requestedScopes) {
//Initialize an empty set, and get the account
HashSet returnedScopes = new HashSet();
Account account = result.getAccount();
/***
In this simple web application, the scopes that were sent in the
body of the request are exactly the ones we want to return. If
however we were building something more complex, and only wanted
to allow a scope to be added if it was verified on the server
side, then we would do something as shown in this for loop. The
'allowScopeForAccount()' method would contain the logic which
would check if the scope is truly allowed for the given account.
for(String scope: requestedScopes){
if(allowScopeForAccount(account, scope)){
returnedScopes.add(scope);
}
}
***/
return requestedScopes;
}
};
AccessTokenResult oauthResult = application.authenticateOauthRequest(
request).using(scopeFactory).execute();
TokenResponse tokenResponse = oauthResult.getTokenResponse();
String json = tokenResponse.toJson();
return json;
}
}
Notice the 10 lines of code right after the getToken() declaration. This is a workaround for Jersey’s lack of providing us with a complete request object. Calling request.getParamter() or request.getParameterMap() will always return null, and since creating an AccessTokenResult object requires the Request object with the body still intact, we must recreate the entire request ourselves.
Finally: Securing your REST endpoint
Ahh, the moment we’ve all been waiting for. Now that we have given our users the ability to target this weather endpoint using Basic and Oauth authentication, it is up to us to figure out which protocol they choose to use.
@Path("/api/weather/{city}")
public class WeatherApi {
@Context
private HttpServletRequest servletRequest;
@Context
private HttpServletResponse servletResponse;
private String weatherResult;
@GET
@Produces(MediaType.APPLICATION_JSON)
public String getWeatherApi(@PathParam("city") final String myCity)
throws Exception {
Application application = StormpathUtils.myClient.getResource(
StormpathUtils.applicationHref, Application.class);
System.out.println(servletRequest.getHeader("Authorization"));
//Make sure this use is allowed to target is endpoint
try {
ApiAuthenticationResult authenticationResult =
application.authenticateApiRequest(servletRequest);
authenticationResult.accept(new AuthenticationResultVisitorAdapter() {
public void visit(ApiAuthenticationResult result) {
System.out.println("Basic request");
URL weatherURL = getURL(myCity);
//Parse weather data into our POJO
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
City city = null;
try {
InputStream in = weatherURL.openStream();
city = mapper.readValue(in, City.class);
} catch (IOException e) {
e.printStackTrace();
}
weatherResult = city.toString() + " °F";
}
public void visit(OauthAuthenticationResult result) {
//Check scopes
if(result.getScope().contains("London") && myCity.equals("London")){
weatherResult = getWeather(myCity) + " °F";;
}
else if(result.getScope().contains("Berlin") && myCity.equals("Berlin")){
weatherResult = getWeather(myCity) + " °F";;
}
else if(result.getScope().contains("SanMateo") && myCity.equals("San Mateo")){
weatherResult = getWeather(myCity) + " °F";;
}
else if(result.getScope().contains("SanFrancisco") && myCity.equals("San Francisco")){
weatherResult = getWeather(myCity) + " °F";;
}
else {
try {
servletResponse.sendError(403);
} catch (IOException e) {
/* To change body of catch statement use File | Settings | File Templates.*/
e.printStackTrace();
}
}
}
});
return weatherResult;
} catch (ResourceException e) {
System.out.println(e.getMessage());
servletResponse.sendError(403);
return "Cannot authenticate user.";
}
}
To do this we use a visitor. We create a visitor for each type of authentication protocol that we expect our clients to use (in our case Basic and Oauth). Based on the type of the ApiAuthenticationResult object, the appropriate visitor will be targeted. Notice how inside the OauthAuthenticationResult visitor, we check the scope of the Oauth token that we received, and appropriately give/forbid access to the requested cities.
When we generated our Oauth token in the sceenshot above, we gave access to view weather in London, Berlin, and San Francisco. Thus we can view London’s weather using Oauth:
However, since San Mateo was not included in the scope of the Oauth token, we cannot see its weather:
Conclusion
Jersey is yet another Java framework that seamlessly integrates with the Stormpath SDK to offer user management, API Key management, Oauth, and more. If you’d like to see more code and even run this application yourself please visit: https://github.com/rkazarin/sample-jersey-webapp
If you want developers to love your API, focus the bulk of your efforts on designing a beautiful one. If you want to boost adoption of your API, consider a tool to make life easier on your users: client libraries. Specifically, Node.js client libraries.
This series will cover our playbook for building a stable, useful Node.js client in detail, in three parts:
Part 1: Need-to-know RESTful Concepts
Part 2: REST client design in Node.js
Part 3: Functionality
If you would like to learn general REST+JSON API design best practices, check out this video. In this article series, we are going to focus exclusively on client-side concepts.
Lastly, keep in mind that while these articles use Node.js, the same concepts apply to any other language client with only syntax differences.
OK. Let’s begin with the RESTful concepts that make for a killer client. After all, if we don’t nail these down, no amount of JavaScript will save us later.
HATEOAS
HATEOAS, usually pronounced ‘Haiti-ohs’, is an acronym for “Hypermedia As The Engine of Application State”. Aside from being an unfortunate acronym, HATEOAS dictates that REST API clients should not know anything about that REST API: a REST client should issue an initial request and everything it needs from that point on can be discovered from the initial response.
HATEOAS is still considered the ideal target for REST API design, but at times, HATEOAS will present a challenge to our REST client design efforts. Think of it this way:
Your end-users will want to use your shiny new client to do the things they know are possible in your API. They will want to invoke known / defined behavior.
You will want to provide them convenience functions to make it super easy for them to interact with your API – things that may not be as easy or possible with standard HTTP requests.
Reconciling 1 and 2 with HATEOAS simply won’t always possible.
Our philosophy takes the pragmatic view: while HATEOS is ideal for automated software agents (like browsers), it is often not as nice for humans that want library functions that address specific needs, so we will diverge from HATEOAS when it makes sense.
REST Resources
Resources transferred between the client and the API server represent things (nouns), not behaviors (verbs). Stormpath is a User Management API, so for us, resources are records like user accounts, groups, and applications.
No matter what your API’s resources are, each resource should always have it’s own canonical URL. This globally unique HREF will identify each resource and only that resource. This point really can’t be stressed enough; canonical URLs are the backbone of RESTful architecture.
In addition to having a canonical URL, resources should be coarse-grained. In practice, this means we return all resource properties in their entirety in the REST payload instead of as partial chunks of data. Assumptions about who will use the resource and how they will use it only make it more difficult to expand your use cases in the future. Besides, coarse-grained resources translate to fewer overall endpoints!
Collection Resources
Collection resources are first-class citizens with their own first-class properties. These properties contain data that in turn describe the collection itself, such as limit and offset.
Collection resources should have a canonical URL and follow a plural naming convention, like /applications (and not /application) to make identification easy. A collection resource always represents potentially many other resources, so plural naming conventions are the most intuitive.
Collections usually support create requests as well as query requests, for example, ‘find all children resources that match criteria X’.
Instance Resources
An instance resource is usually represented as a child of some parent collection. In the example below, the URI references a particular application within the /applications collection. The implication is that if you interact with this endpoint, you interact with a single application.
/applications/8sZxUoExA30mp74
For the most part, instance resources only need to support read, update, and delete operations. While not a hard and fast rule, reserving create for collections is a common convention in REST API design, especially if you want to generate unique identifiers for each newly-created resource.
Resource Code Examples
Ok, now the fun stuff – code!
If we are to translate these REST resource concepts to working code, it would make sense to have code artifacts that represent both collection and instance resources.
Here’s an example of what it might look like to define a very general resource concept in a Node.js library:
var util = require('util');
function Resource(...) { ... }
util.inherits(Resource, Object);
someResource.href
We’re using JavaScript’s prototypical inheritance here to simulate classical Object Oriented inheritance. We’ve found this to be the easiest to understand abstraction for most developers using code libraries, so we went with this paradigm.
As you can see, The Resource ‘class’ above takes advantage of the standard Node util library to create a resource constructor function. If you want to simulate a classical OO hierarchy, util is a great way to do it.
Next, we’ll extend this general resource class to create more specific Instance and Collection resource classes.
As mentioned, you’ll notice save and delete methods on InstanceResource, but no create. The callback on save returns either an error or the successfully saved object; delete has no object to return, so only an error might be provided to the callback. Both methods are called asynchronously after the operation is complete.
So what’s the takeaway? You can save or delete individual things, but not necessarily entire collections. Which leads us to our next resource class:
function CollectionResource(...) {...}
util.inherits(CollectionResource, Resource);
aCollResource.each(function (item, callback) {
...
}, function onCompletion(err) {
...
});
aCollResource.eachSeries
aCollResource.map
aCollResource.filter
... other async.js methods ...
CollectionResource can support a number of helper functions, but the most common is each. each takes an iterator function which is invoked asynchronously for every instance in the collection.
applications.each(function(app, callback){
console.log(app);
callback();
}, function finished(err) {
if (err) console.log(‘Error: ‘ + err);
});
This example uses each to simply log all the instance resources.
As a great convenience, we made the decision early on to assimilate all of async.js’ collection utility functions into all Collection resources. This allows developers to call Stormpath methods using the semantics of async.js and allows the client to delegate those methods to the corresponding async.js functions behind the scenes. Eliminating even just one package to import has proven to be really convenient, as we’ll discuss more in part 3. We’re big fans of async.js.
(Note that async.js requires you to invoke a callback method when you’re done with a given iteration step.)
That’s it for the RESTful groundwork! We have a number of other articles and videos pertaining to REST security, linking, POST vs PUT, and more on the blog if you’re interested.
Part two of this series will be all about the nitty-gritty details of coding the client. Expect sections on encapsulation, public vs. private API implementation, and our component architecture. Stay tuned!
API Management with Stormpath
Stormpath makes it easy to manage your API keys and authenticate developers to your API service. Learn more in our API Key Management Guide and try it for free!
Welcome to Part Two of our series on Node.js Client Libraries. This post serves as our guide to REST client design and architecture. Be sure to check out Part One on Need-To-Know RESTful Concepts before reading on.
API Encapsulation
Before sinking our teeth into resources and architecture, let’s talk about encapsulation. At Stormpath, we like to clearly separate the public and private portions of our API client libraries, aka ‘SDKs’ (Software Development Kit).
All private functionality is intentionally encapsulated, or hidden from the library user. This allows the project maintainers to make frequent changes like bug fixes, design and performance enhancements, all while not impacting users. This leads to a much greater level of maintainability, allowing the team to deliver better quality software, faster, to our user community. And of course, an easier-to-maintain client results in less friction during software upgrades and users stay happy.
To achieve this, your Node.js client should only expose users to the public version of your API and never the private, internal implementation. If you’re coming from a more traditional Object Oriented world, you can think of the public API as behavior interfaces. Concrete implementations of those interfaces are encapsulated in the private API. In Node.js too, functions and their inputs and output should rarely change. Otherwise you risk breaking backwards compatibility.
Encapsulation creates lot of flexibility to make changes in the underlying implementation. That being said, semantic versioning is still required to keep your users informed of how updates to the public will affect their own code. Most developers will already be familiar semantic versioning, so it’s an easy usability win.
Encapsulation In Practice
We ensure encapsulation primarily with two techniques: Node.js module.exports and the ‘underscore prefix’ convention.
module.exports
Node.js gives you the ability to expose only what you want via its module.exports capability: any object or function in a module’s module.exports object will be available to anyone that calls.
This is a big benefit to the Node.js ecosystem and helps improve encaspsulation goals better than traditional JavaScript environments.
Underscore Names
Additionally we use the ‘underscore prefix’ convention for objects or functions that are considered private by the development team but still accessible at runtime because of JavaScript’s weak encapsulation behavior. That is, any object or function that starts with the underscore _ character is considered private and its state or behavior can change, without warning or documentation, on any given release.
The takeaway is that external developers should never explicitly code against anything that has a name that starts with an underscore. If they see a name that starts with an underscore, it’s simply ‘hands off’.
Alternatively, other libraries use @public and @private annotations in their JS docs as a way of indicating what is public/allowed vs. private/disallowed. However, we strongly prefer the underscore convention because anyone reading or writing code that does not have immediate access to the documentation can still see what is public vs private. For example it is common when browsing code in GitHub or Gists that annotations in documentation are not easily available. However, you can still always tell that underscore-prefixed methods are to be considered private.
Either way, you need to consistently convey which functions to use and which to leave alone. You may want to omit the private API from publicly hosted docs to prevent confusion.
Public API
The public API consists of all non-private functions, variables, classes, and builder/factory functions.
This may be surprising to some, but object literals used as part of configuration are also part of the public API. Think of it like this: if you tell people to use a function that requires an object literal, you are making a contract with them about what you support. It’s better to just maintain backwards and forwards compatibility with any changes to these object literals whenever possible.
Prototypical OO Classes
We use prototypical inheritance and constructor functions throughout the client, but the design reflects a more traditional OO style. We’ve found this makes sense to most of our customers of all skill/experience levels.
Stormpath is a User Management API, so our classes represent common user objects like Account, in addition to more generic classes, like ApiKey. A few classes used as examples in this post:
Client
ApiKey
Application
Directory
Account
Builder Functions
Node.js and other APIs often use method chaining syntax to produce a more readable experience. You may have also heard of this referred to as a Fluent Interface.
In our client, it’s possible to perform any API operation using a client instance. For example, getApplications obtains all Applications by using the client and method chaining:
There are two important things to note from this getApplications example:
Query construction with where, startsWith and orderBy functions is synchronous. These are extremely lightweight functions that merely set a variable, so there is no I/O overhead and as such, do not need to be asynchronous.
The execute function at the end is asynchronous and actually does the work and real I/O behavior. This is always asynchronous to comply with Node.js performance best practices.
Did you notice getApplications does not actually return an applications list but instead returns a builder object?
A consistent convention we’ve added to our client library is that get* methods will either make an asynchronous call or they will return a builder that is used to make an asynchronous call.
But we also support direct field access, like client.foo, and this implies a normal property lookup on a dictionary and a server request will not be made.
So, calling a getter function does something more substantial. Both still retain familiar dot notation to access internal properties. This convention creates a clear distinction between asynchronous behavior and simple property access, and the library user knows clearly what to expect in all cases.
Writing code this way helps with readability too – code becomes more simple and succinct, and you always know what is going on.
Base Resource Implementation
The base resource class has four primary responsibilities:
Property manipulation methods – Methods (functions) with complicated interactions
Dirty Checking – Determines whether properties have changed or not
Reference to DataStore – All our resource implementations represent an internal DataStore object (we’ll cover this soon)
Lazy Loading – Loads linked resources
Resource and all of its subclasses are actually lightweight proxies around a DataStore instance, which is why the constructor function below takes two inputs:
data (an object of name/value pairs)
A DataStore object.
var utils = require('utils');
function Resource(data, dataStore) {
var DataStore = require('../ds/DataStore');
if (!dataStore && data instanceof DataStore){
dataStore = data;
data = null;
}
data = data || {};
for (var key in data) {
if (data.hasOwnProperty(key)) {
this[key] = data[key];
}
}
var ds = null; //private var, not enumerable
Object.defineProperty(this, 'dataStore', {
get: function getDataStore() {
return ds;
},
set: function setDataStore(dataStore) {
ds = dataStore;
}
});
if (dataStore) {
this.dataStore = dataStore;
}
}
utils.inherits(Resource, Object);
module.exports = Resource;
When CRUD operations are performed against these resource classes, they just delegate work to the backend DataStore. As the DataStore is a crucial component of the private API, we keep it hidden using object-defined private property semantics. You can see this in practice with the public getters and setters around the private attribute above. This is one of the few ways to implement proper encapsulation in JavaScript.
If you remember to do just two things when implementing base resource classes, let them be:
Copy properties over one-to-one
Create a reference to a DataStore object to use later
Base Instance Resource Implementation
InstanceResource is a subclass of Resource. The base instance resource class prototypically defines functions such as save and delete, making them available to every concrete instance resource.
Note that the saveResource and deleteResource functions delegate work to the DataStore.
var utils = require('utils');
var Resource = require('./Resource');
function InstanceResource() {
InstanceResource.super_.apply(this, arguments);
}
utils.inherits(InstanceResource, Resource);
InstanceResource.prototype.save = function saveResource(callback) {
this.dataStore.saveResource(this, callback);
};
InstanceResource.prototype.delete = function deleteResource(callback) {
this.dataStore.deleteResource(this, callback);
};
In traditional object oriented programming, the base instance resource class would be an abstract. It isn’t meant to be instantiated directly, but instead should be used to create concrete instance resources like Application:
var utils = require('utils');
var InstanceResource = require('./InstanceResource');
function Application() {
Application.super_.apply(this, arguments);
}
utils.inherits(Application, InstanceResource);
Application.prototype.getAccounts = function
getApplicationAccounts(/* [options,] callback */) {
var self = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var options = (args.length > 0) ? args.shift() : null;
return self.dataStore.getResource(self.accounts.href, options,
require('./Account'), callback);
};
How do you support variable arguments in a language with no native support for function overloading? If you look at the getAccounts function on Applications, you’ll see we’re inspecting the argument stack as it comes into the function.
The comment notation indicates what the signature could be and brackets represent optional arguments. These signal to the client’s maintainer(s) (the dev team) what the arguments are supposed to represent. It’s a handy documentation syntax that makes things clearer.
options is an object literal of name/value pairs and callback is the function to be invoked. The client ultimately directs the work to the DataStore by passing in an href. The DataStore uses the href to know which resource it’s interacting with server-side.
Usage Paradigm
Let’s take a quick look at an example JSON resource returned by Stormpath:
Every JSON document has an href field that exists in all resources, everywhere. JSON is exposed as data via the resource and can be referenced via standard dot notation like any other JavaScript object.
Applications using a client will often have an href for one concrete resource and need access to many others. In this case, the client should support a method (e.g. getAccount) that takes in the href they have, to obtain the ones they need.
In the above code sample,getAccount returns the corresponding Account instance, and then the account can be immediately used to obtain its parent Directory object. Notice that you did not have to use the client again!
The reason this works is that the Account instance is not a simple object literal. It is instead a proxy, that wraps a set of data and the underlying DataStore instance. Whenever it needs to do something more complicated than direct property access, it can automatically delegate work to the datastore to do the heavy lifting.
This proxy pattern is popular because it allows for many benefits, such as programmatic interaction between references, linked references, and resources. In fact, you can traverse the entire object graph with just the initial href! That’s awfully close to HATEOS! And it dramatically reduces boilerplate in your code by alleviating the need to repeat client interaction all the time.
So how does this work under the hood? When your code calls account.getDirectory, the underlying (wrapped) DataStore performs a series of operations under the hood:
Create the HTTP request
Execute the request
Receive a response
Marshal the data into an object
Instantiate the resource
Return it to the caller
Client Component Architecture
Clearly, the DataStore does most of the heavy lifting for the client. There’s actually a really good reason for this model: future enhancements.
Your client will potentially handle a lot of complexity that is simpler in the long run to decouple from resource implementations. Because the DataStore is part of the private API, we can leverage it to plugin new functionality and add new features without changing the Public API at all. The client will just immediately see the benefits.
Here is a really good example of this point. The first release of our SDK Client did not have caching built in. Any time a Stormpath-backed app called getAccount, getDirectory, or any number of other methods, the client always had to execute an HTTP request to our servers. This obviously introduced latency to the application and incurred an unnecessary bandwidth hit.
However our DataStore-centric component architecture allowed us to go back in and plug in a cache manager. The instant this was enabled, caching became a new feature available to everyone and no one had to change their source code. That’s huge.
Anyway, let’s walk through the sequence of steps in a request, to see how the pieces work together.
First, the DataStore looks up the cache manager, finds a particular region in that cache, and checks if the requested resource is in cache. If it is, the client returns the object from the cache immediately.
If the object is not in cache, the DataStore interacts with the RequestExecutor. The RequestExecutor is another DataStore component that in turn delegates to two other components: an AuthenticationStrategy and the RequestAuthenticator.
REST clients generally authenticate by setting values in the authorization header. This approach is incredibly convenient because it means swapping authentication strategies is a simple matter of changing out the header. All that is required is to change out the AuthenticationStrategy implementation and that’s it – no internal code changes required!
Many clients additionally support multiple/optional authentication schemes. More on this topic in part 3.
After authentication, the RequestExecutor communicates the outgoing request to the API server.
Finally, the ResourceFactory takes the raw JSON returned by the API server and invokes a constructor function to create the instance resource that wraps (proxies) this data, and again, the DataStore.
All of the client components represented in this diagram should be pluggable and swappable based on your particular implementation. To make this a reality as you architect the client, try to adhere to the Single Responsibility Principle: ensure that your functions and classes do one and only one thing so you can swap them out or remove them without impacting other parts of your library. If you have too many branching statements in your code, you might be breaking SRP and this could cause you pain in the future.
And there you have it! Our approach to designing a user-friendly and extremely maintainable client to your REST API. Check back for Part Three and a look at querying, authentication, and plugins!
API Management with Stormpath
Stormpath makes it easy to manage your API keys and authenticate developers to your API service. Learn more in our API Key Management Guide and try it for free!
Welcome to Part Two of our series on Node.js Client Libraries. This post serves as our guide to REST client design and architecture. Be sure to check out Part One on Need-To-Know RESTful Concepts before reading on.
API Encapsulation
Before sinking our teeth into resources and architecture, let’s talk about encapsulation. At Stormpath, we like to clearly separate the public and private portions of our API client libraries, aka ‘SDKs’ (Software Development Kit).
All private functionality is intentionally encapsulated, or hidden from the library user. This allows the project maintainers to make frequent changes like bug fixes, design and performance enhancements, all while not impacting users. This leads to a much greater level of maintainability, allowing the team to deliver better quality software, faster, to our user community. And of course, an easier-to-maintain client results in less friction during software upgrades and users stay happy.
To achieve this, your Node.js client should only expose users to the public version of your API and never the private, internal implementation. If you’re coming from a more traditional Object Oriented world, you can think of the public API as behavior interfaces. Concrete implementations of those interfaces are encapsulated in the private API. In Node.js too, functions and their inputs and output should rarely change. Otherwise you risk breaking backwards compatibility.
Encapsulation creates lot of flexibility to make changes in the underlying implementation. That being said, semantic versioning is still required to keep your users informed of how updates to the public will affect their own code. Most developers will already be familiar semantic versioning, so it’s an easy usability win.
Encapsulation In Practice
We ensure encapsulation primarily with two techniques: Node.js module.exports and the ‘underscore prefix’ convention.
module.exports
Node.js gives you the ability to expose only what you want via its module.exports capability: any object or function in a module’s module.exports object will be available to anyone that calls.
This is a big benefit to the Node.js ecosystem and helps improve encaspsulation goals better than traditional JavaScript environments.
Underscore Names
Additionally we use the ‘underscore prefix’ convention for objects or functions that are considered private by the development team but still accessible at runtime because of JavaScript’s weak encapsulation behavior. That is, any object or function that starts with the underscore _ character is considered private and its state or behavior can change, without warning or documentation, on any given release.
The takeaway is that external developers should never explicitly code against anything that has a name that starts with an underscore. If they see a name that starts with an underscore, it’s simply ‘hands off’.
Alternatively, other libraries use @public and @private annotations in their JS docs as a way of indicating what is public/allowed vs. private/disallowed. However, we strongly prefer the underscore convention because anyone reading or writing code that does not have immediate access to the documentation can still see what is public vs private. For example it is common when browsing code in GitHub or Gists that annotations in documentation are not easily available. However, you can still always tell that underscore-prefixed methods are to be considered private.
Either way, you need to consistently convey which functions to use and which to leave alone. You may want to omit the private API from publicly hosted docs to prevent confusion.
Public API
The public API consists of all non-private functions, variables, classes, and builder/factory functions.
This may be surprising to some, but object literals used as part of configuration are also part of the public API. Think of it like this: if you tell people to use a function that requires an object literal, you are making a contract with them about what you support. It’s better to just maintain backwards and forwards compatibility with any changes to these object literals whenever possible.
Prototypical OO Classes
We use prototypical inheritance and constructor functions throughout the client, but the design reflects a more traditional OO style. We’ve found this makes sense to most of our customers of all skill/experience levels.
Stormpath is a User Management API, so our classes represent common user objects like Account, in addition to more generic classes, like ApiKey. A few classes used as examples in this post:
Client
ApiKey
Application
Directory
Account
Builder Functions
Node.js and other APIs often use method chaining syntax to produce a more readable experience. You may have also heard of this referred to as a Fluent Interface.
In our client, it’s possible to perform any API operation using a client instance. For example, getApplications obtains all Applications by using the client and method chaining:
There are two important things to note from this getApplications example:
Query construction with where, startsWith and orderBy functions is synchronous. These are extremely lightweight functions that merely set a variable, so there is no I/O overhead and as such, do not need to be asynchronous.
The execute function at the end is asynchronous and actually does the work and real I/O behavior. This is always asynchronous to comply with Node.js performance best practices.
Did you notice getApplications does not actually return an applications list but instead returns a builder object?
A consistent convention we’ve added to our client library is that get* methods will either make an asynchronous call or they will return a builder that is used to make an asynchronous call.
But we also support direct field access, like client.foo, and this implies a normal property lookup on a dictionary and a server request will not be made.
So, calling a getter function does something more substantial. Both still retain familiar dot notation to access internal properties. This convention creates a clear distinction between asynchronous behavior and simple property access, and the library user knows clearly what to expect in all cases.
Writing code this way helps with readability too – code becomes more simple and succinct, and you always know what is going on.
Base Resource Implementation
The base resource class has four primary responsibilities:
Property manipulation methods – Methods (functions) with complicated interactions
Dirty Checking – Determines whether properties have changed or not
Reference to DataStore – All our resource implementations represent an internal DataStore object (we’ll cover this soon)
Lazy Loading – Loads linked resources
Resource and all of its subclasses are actually lightweight proxies around a DataStore instance, which is why the constructor function below takes two inputs:
data (an object of name/value pairs)
A DataStore object.
var utils = require('utils');
function Resource(data, dataStore) {
var DataStore = require('../ds/DataStore');
if (!dataStore && data instanceof DataStore){
dataStore = data;
data = null;
}
data = data || {};
for (var key in data) {
if (data.hasOwnProperty(key)) {
this[key] = data[key];
}
}
var ds = null; //private var, not enumerable
Object.defineProperty(this, 'dataStore', {
get: function getDataStore() {
return ds;
},
set: function setDataStore(dataStore) {
ds = dataStore;
}
});
if (dataStore) {
this.dataStore = dataStore;
}
}
utils.inherits(Resource, Object);
module.exports = Resource;
When CRUD operations are performed against these resource classes, they just delegate work to the backend DataStore. As the DataStore is a crucial component of the private API, we keep it hidden using object-defined private property semantics. You can see this in practice with the public getters and setters around the private attribute above. This is one of the few ways to implement proper encapsulation in JavaScript.
If you remember to do just two things when implementing base resource classes, let them be:
Copy properties over one-to-one
Create a reference to a DataStore object to use later
Base Instance Resource Implementation
InstanceResource is a subclass of Resource. The base instance resource class prototypically defines functions such as save and delete, making them available to every concrete instance resource.
Note that the saveResource and deleteResource functions delegate work to the DataStore.
var utils = require('utils');
var Resource = require('./Resource');
function InstanceResource() {
InstanceResource.super_.apply(this, arguments);
}
utils.inherits(InstanceResource, Resource);
InstanceResource.prototype.save = function saveResource(callback) {
this.dataStore.saveResource(this, callback);
};
InstanceResource.prototype.delete = function deleteResource(callback) {
this.dataStore.deleteResource(this, callback);
};
In traditional object oriented programming, the base instance resource class would be an abstract. It isn’t meant to be instantiated directly, but instead should be used to create concrete instance resources like Application:
var utils = require('utils');
var InstanceResource = require('./InstanceResource');
function Application() {
Application.super_.apply(this, arguments);
}
utils.inherits(Application, InstanceResource);
Application.prototype.getAccounts = function
getApplicationAccounts(/* [options,] callback */) {
var self = this;
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var options = (args.length > 0) ? args.shift() : null;
return self.dataStore.getResource(self.accounts.href, options,
require('./Account'), callback);
};
How do you support variable arguments in a language with no native support for function overloading? If you look at the getAccounts function on Applications, you’ll see we’re inspecting the argument stack as it comes into the function.
The comment notation indicates what the signature could be and brackets represent optional arguments. These signal to the client’s maintainer(s) (the dev team) what the arguments are supposed to represent. It’s a handy documentation syntax that makes things clearer.
options is an object literal of name/value pairs and callback is the function to be invoked. The client ultimately directs the work to the DataStore by passing in an href. The DataStore uses the href to know which resource it’s interacting with server-side.
Usage Paradigm
Let’s take a quick look at an example JSON resource returned by Stormpath:
Every JSON document has an href field that exists in all resources, everywhere. JSON is exposed as data via the resource and can be referenced via standard dot notation like any other JavaScript object.
Applications using a client will often have an href for one concrete resource and need access to many others. In this case, the client should support a method (e.g. getAccount) that takes in the href they have, to obtain the ones they need.
In the above code sample,getAccount returns the corresponding Account instance, and then the account can be immediately used to obtain its parent Directory object. Notice that you did not have to use the client again!
The reason this works is that the Account instance is not a simple object literal. It is instead a proxy, that wraps a set of data and the underlying DataStore instance. Whenever it needs to do something more complicated than direct property access, it can automatically delegate work to the datastore to do the heavy lifting.
This proxy pattern is popular because it allows for many benefits, such as programmatic interaction between references, linked references, and resources. In fact, you can traverse the entire object graph with just the initial href! That’s awfully close to HATEOS! And it dramatically reduces boilerplate in your code by alleviating the need to repeat client interaction all the time.
So how does this work under the hood? When your code calls account.getDirectory, the underlying (wrapped) DataStore performs a series of operations under the hood:
Create the HTTP request
Execute the request
Receive a response
Marshal the data into an object
Instantiate the resource
Return it to the caller
Client Component Architecture
Clearly, the DataStore does most of the heavy lifting for the client. There’s actually a really good reason for this model: future enhancements.
Your client will potentially handle a lot of complexity that is simpler in the long run to decouple from resource implementations. Because the DataStore is part of the private API, we can leverage it to plugin new functionality and add new features without changing the Public API at all. The client will just immediately see the benefits.
Here is a really good example of this point. The first release of our SDK Client did not have caching built in. Any time a Stormpath-backed app called getAccount, getDirectory, or any number of other methods, the client always had to execute an HTTP request to our servers. This obviously introduced latency to the application and incurred an unnecessary bandwidth hit.
However our DataStore-centric component architecture allowed us to go back in and plug in a cache manager. The instant this was enabled, caching became a new feature available to everyone and no one had to change their source code. That’s huge.
Anyway, let’s walk through the sequence of steps in a request, to see how the pieces work together.
First, the DataStore looks up the cache manager, finds a particular region in that cache, and checks if the requested resource is in cache. If it is, the client returns the object from the cache immediately.
If the object is not in cache, the DataStore interacts with the RequestExecutor. The RequestExecutor is another DataStore component that in turn delegates to two other components: an AuthenticationStrategy and the RequestAuthenticator.
REST clients generally authenticate by setting values in the authorization header. This approach is incredibly convenient because it means swapping authentication strategies is a simple matter of changing out the header. All that is required is to change out the AuthenticationStrategy implementation and that’s it – no internal code changes required!
Many clients additionally support multiple/optional authentication schemes. More on this topic in part 3.
After authentication, the RequestExecutor communicates the outgoing request to the API server.
Finally, the ResourceFactory takes the raw JSON returned by the API server and invokes a constructor function to create the instance resource that wraps (proxies) this data, and again, the DataStore.
All of the client components represented in this diagram should be pluggable and swappable based on your particular implementation. To make this a reality as you architect the client, try to adhere to the Single Responsibility Principle: ensure that your functions and classes do one and only one thing so you can swap them out or remove them without impacting other parts of your library. If you have too many branching statements in your code, you might be breaking SRP and this could cause you pain in the future.
And there you have it! Our approach to designing a user-friendly and extremely maintainable client to your REST API. Check back for Part Three and a look at querying, authentication, and plugins!
API Management with Stormpath
Stormpath makes it easy to manage your API keys and authenticate developers to your API service. Learn more in our API Key Management Guide and try it for free!
Welcome to Part Three of our guide to Node.js REST clients. This third and final blogpost will wrap up the series with a look at topics like querying, caching, API authentication, and lessons learned the hard way.
Robust querying support reduces the effort required to use your API, especially if you implemented it with familiar conventions.
For instance, say your client user needs to interact with a particular collection resource…hopefully a plausible scenario! They would probably write something along these lines:
Assuming the groups are not in cache, a request needs to be automatically sent to the server to obtain the account’s groups, for example:
GET https://api.stormpath.com/v1/accounts/a1b2c3/groups
This is a great start, but ultimately a limited one. What happens the client user wants to specify search parameters? We need more powerful request query capabilities.
Query Parameters with Object Literals
An improvement is to accept an object literal to populate query parameters. This is a common technique in Node.js that specifies query parameters or skips the optional object and passes in the proceeding callback function.
GET https://api.stormpath.com/v1/accounts/a1b2c3/groups?name=foo*&description=*test*&orderBy=name%20desc&limit=100
The client simply takes the name/value pairs on the object and translates them to url-encoded query parameters. We accept an object literal rather than query strings because no one wants to mess with URL encoding. This is a perfect place to offload work from your client user to the client.
Fluent API Queries
While the above approach is nice and convenient, it still requires some specific knowledge of the API’s specific query syntax. In the above example, to find any group that starts with the name foo, you need to know to use a wildcard matching asterisk at the end of the search term, i.e.
account.getGroups({
name: 'foo*', // for comparison, in SQL, this looks like
// 'where name like foo%'
... etc ...
While it is easy enough to learn these syntax additions, it is even easier for client users if they have a Fluent API to help them construct queries in a fully explicit and self-documenting way. IDEs with intelligent auto-completion can even help tell you what methods are available while writing your query, helping you write queries much faster!
Consider the following example. The resulting query to the server is no different than the one above that used an object literal, but the query author now does not need to know any syntax-specific modifiers:
As expected, this results in the same HTTP request:
GET https://api.stormpath.com/v1/accounts/a1b2c3/groups?name=foo*&description=*test*&orderBy=name%20desc&limit=100
As you can see, the query author just chains method calls and then the client implementation constructs the relevant query parameter map and executes the request.
In addition to being easier to read and perhaps better self-documenting, this approach has some other very compelling benefits:
Because functions represent known queryable properties, it is not possible to specify query criteria that is not supported as a function.
Similarly, all possible functionality, like ordering and size limiting, are discoverable just by inspecting functions and code – there is less of a need to read external documentation! This is a huge help to those who just want to write queries quickly and move on – definitely a nice usability benefit.
It is much harder, if not impossible, to form a syntactically incorrect query. Query authors will likely ‘get it right’ the first time they write a query, thereby reducing bugs in their own code and increasing their overall happiness with your library.
There is, of course, a downside to supporting a fluent API for querying: implementation effort. It definitely requires a little more time and care to develop a builder/chaining API that client users can interact with easily. However, because of the self-documenting and syntatic checking nature, we feel fluent APIs are one of those features that really takes your library to the next level and can only make users happier.
Even with this downside though, there is one side benefit: when you’re ready to add a fluent query API to your library, your implementation can build directly on top of the object literal query capability described above. This means you can build and release your library in an iterative fashion: build in the object literal query support first, ensure that works, and then release your library.
When you’re ready, you can create a fluent query implementation that just generates the same exact object literals that a client user could have specified. This means you’re building on top of something that already works – there is no need to re-write another query mechanism from scratch, saving you time.
Caching
Our SDK utilizes a CacheManager, a component used by the DataStore to cache results that come back from the server. While the cache manager itself is a very simple concept, caching is extremely important for performance and efficiency. This is especially true for clients that communicate with REST servers over the public Internet. Cache if you can!
The CacheManager reflects a pluggable design. Users can configure the client to use the default in-memory implementation, or they can configure (plug in) out-of-the-box support for Memcache or Redis. This is a big benefit to many production-grade apps that run on more than one web server. Additionally, the CacheManager API itself is very simple; you can also implement and plug in new ones easily if the existing three implementations do not suit your needs.
Regardless of the specific CacheManager implementation selected, the client instance can access one or more Cache objects managed by the CacheManager. Typically, each Cache object represents a single region in the overall cache memory space (or cache cluster) where data can be stored. Each cache region typically has a specific Time-To-Live and Time-To-Idle setting that applies to all data records in that cache region.
Because of this per-region capability, the Stormpath SDK stores resource instances in a region by type. All Accounts are in one region, all Groups in another, etc. This allows the client user to configure caching policies for each data type as they prefer, based on their application’s data consistency needs.
So, how does this work internally in the Client?
Because of RESTful philosophies (covered in Part One of this blog series), every resource should have a globally-unique canonical HREF that uniquely identifies it among all others. Because of this canonical and unique nature, that means a resource’s HREF is a perfect candidate for cache key. Cache entries under a href key will never collide, so we’ll use the HREF as the cache key.
This allows a client DataStore to obtain a cached version of a resource before attempting to send a REST API server HTTP request. More importantly, the DataStore should be able to get an element out of the cache by passing in a resource HREF. In the example below, the callback function takes an error or the raw object stored in the cache.
var cache = cacheManager.getCache(regionName);
cache.ttl //time to live
cache.tti //time to idle
cache.get(href, function(err, obj) {
...
});
At Stormpath, we only store name/value pairs in the cache and nothing else. The data in our cache is the same stuff sent to and from the server.
client.getAccount(href, function(err, acct) {...});
// in the DataStore:
var cache = cacheManager.getCache(‘accounts’);
cache.get(href, function(err, entry) {
if (err) return callback(err);
if (entry) {
... omitted for brevity ...
return callback(entry.value);
}
//otherwise, cache miss – execute a request:
requestExecutor.get(href, function(err, body) {
//1. cache body
//2. convert to Resource instance
//3. invoke callback w/ instance
}
}
When getAccount is called, the client first interacts with cacheManager to get the cache region and then requests the cached object. If the object is found, it executes the callback. If the object isn’t found, it executes a request to the server using requestExecutor.
The fallback logic is fairly straightforward: Check the cache before issuing a request to the server. The beautiful thing is that your client users don’t have to change any of their code – they can just navigate the object tree regardless of whether the data is held in cache.
Recursive Caching
Recursive caching is, in a word, important.
When you request a resource from the server, you can use something called reference expansion or link expansion to not only obtain the desired resource, but any of its linked/referenced resources as well.
This means any expanded response JSON representation can be an object graph: the requested resource plus any other nested JSON objects for any linked resources. Each one of these resources needs to be cached independently (again, keyed based on each resource’s href).
Recursive caching is, then, basically walking this resource object graph, and for each resource found, caching that resource by its href key. Our implementation of this ‘graph walk’ utilizes recursion because it was simpler for us to implement and it’s fairly elegant. This is why it is called recursive caching. If we implemented it via iteration instead, I suppose we would have called it iterative caching.
Authentication
Secure authentication is near and dear to our hearts at Stormpath, which is why we recommend defaulting API authentication in your client to a digest-based scheme instead of HTTP basic. Although basic authentication is the simplest form of HTTP authentication, it is probably the one with the most security risks:
The secret (‘password’) is sent in an HTTP header essentially in plain text. This means HTTP basic can very easily expose raw passwords to potential attackers in any part of infrastructure that does not use TLS (previously known as SSL).
HTTP Basic authentication allows embedding the id and password in the URL, and this is never a good idea: URLs are logged all the time for analytics and reporting, exposing the secret password to anyone.
HTTP Basic authentication does not prevent Man-in-the-Middle (MitM) attacks at any point before or after network transmission. This is true even if you’re using TLS.
Because of these perils, we only advocate supporting HTTP Basic authentication if you have no other choice, and instead use what is known as a Digest-based authentication scheme. While digest authentication schemes are out of scope of this blogpost, OAuth 1.0a and Stormpath’s sauthc algorithm are good, very secure examples.
That being said, clients should offer basic authentication as an optional strategy for environments where digest schemes are incompatible. For instance, Google App Engine manipulates HTTP request object headers before sending requests out on the wire – the exact behavior that digest algorithms protect against. Our original clients didn’t work on GAE for this reason until we implemented optional basic auth.
Note: Basic authentication can only ever be implemented over TLS. It’s never okay to use basic without TLS, it’s simply too easy to find the raw password value.
Because of the need for this occasional customization, clients can be configured to specify an alternative Authentication Scheme as a constant object. For example:
AuthenticationScheme.SAUTHC1
AuthenticationScheme.Basic
AuthenticationScheme.OAUTH10a
… etc …
For example, if a client user needed to use BASIC authentication:
var client = new Stormpath.Client({
authcScheme: ‘basic’ //defaults to 'sauthc1' otherwise
});
If they don’t specify a config value, default to the most secure option your API server supports.
Plugins
A well-defined API permits the client to support plugins/extensions without the support of type safety or interfaces. Duck typing helps too.
For example, Stormpath’s RequestExecutor relies on the Request.js module (as do many other Node.js applications). However, if anyone wanted to modify our client to use a different HTTP request library, they could implement an object with the same functions and signatures of the RequestExecutor API and just plug it in to the client configuration.
This flexibility becomes important as your client supports a broader variety of environments and applications.
Promises and Async.js
Callback Hell: The bane of Node.js library maintainers and end-users alike. Luckily, there are a couple good options to keep your Node.js code readable. For instance, Promises promote traceability even in async environments executing concurrently.
var promise = account.getGroups();
promise.then(function() {
//called on success
}, function() {
//called on error
}, function() {
//called during progress
});
However, excessive use of Promises has been linked to degraded application performance – use them in a calculated fashion. Since Promises are a fairly new design approach in Node.js, most Node.js applications today use callbacks instead. If you want to stick with the dominant approach, and still avoid highly-nested functions, take a look at the fantastic async.js module.
Check out this waterfall style control flow!
async.waterfall([
function(callback) {
callback(null, 'one', 'two');
},
function(arg1, arg2, callback) {
// arg1 now equals 'one' and arg2 now equals 'two'
callback(null, 'three');
},
function(arg1, callback) {
// arg1 now equals 'three'
callback(null, 'done');
}],
function (err, result) {
// result now equals 'done'
}
);
This code is readable – it looks like more readable imperative-style programming code, but because async.js is managing invocation, the code is still asynchronous and conforms to Node.js performance best practices.
As we mentioned previously in Part One, all of the Stormpath SDK Collections inherit async.js iterator functions so you can use collections in the same way. Convenient!
Stormpath Node.js Client
The Stormpath Node.js client is Apache licensed and 100% open source. Now that you’ve gotten an idea for how we built ours, try cloning it for more real-world examples.
Stormpath makes it easy to manage your API keys and authenticate developers to your API service. Learn more in our API Key Management Guide and try it for free!