I'm building an API and trying to figure out Authentication in a number of contexts.
Sessions and Password Authentication
The API needs to serve client-side applications we create and deploy, and handle authenticated requests using a password. It's not a great idea to send the password with every request, so it makes more sense to first hit a login endpoint and get a session id. The webapp in question is written in AngularJS, and should track its own session in localStorage to mitigate session hijacking and remove the dependency on cookies to track sessions.
The webapp would need to send the session identifier with every request, and currently does so in the body of the request. This fragments pretty easily and becomes tightly coupled with the API. I would much rather pass all authentication information in one way—through a header, preferably—instead of in a number of different fields spread across the request body, url and headers.
Session Storage
Redis is awesome, of course. Session storage is straightforward and automatically garbage-collects. Unfortunately, sessions in redis are difficult to manage: I cannot easily revoke all sessions for a given user. Adding that capability by storing sessions in a true redis-datastructure instead of the global keyspace removes the ability to add keyed TTLs. My current solution is to store a list of sessions in the MongoDB user collection, and garbage-collect expired sessions on session activity (login/logout, for instance).
The sessions are stored in redis with the connect-redis module, but as they are sent with every request aren't included in the cookies. At the moment, I have a small piece of middleware that takes the session identifier out of the request body and puts it into a req.cookies
object.
var express = require('express');
var RedisStore = require('connect-redis')(require('connect'));
var app = express();
app.use(function(req, res, next) {
req.cookies = {session: req.body.session};
});
app.use(express.session({
store: new RedisStore({
client: redisClient,
prefix: 'session:'
}),
key: 'session',
secret: 'all mine'
});
This approach works fine, except that express.session
ends up setting the cookie when express responds, and that's not the desired behavior.
How do I set this up properly in the context of Express?
API Keys
Our API should also support API keys for third-party applications to gain limited and controlled access to our system. The most common mechanism I know of to do this is to distribute API keys to interested developers, and have the developer pass the API key in as part of the request. This runs into the same dilemma that session/password authentication runs into: every API expects the API key in a different part of the request, from the body to the url to the headers.
Expansion and Open Standards
While we do not plan on supporting Open authentication standards like OpenAuth and OpenID at initial release, we do wish to create a framework in which the addition of said standards is straightforward. Part of that could be to unify how authorization credentials are handed to the API, as with session/password and API Key backed authentication.
Another question asks whether customizing the HTTP Authorization
header is a good idea, or if a custom header is a better idea.
CRUD Support
In order to support the CRUD paradigm for RESTful APIs, it makes sense to not provide authentication information in the body as that would limit all API requests to POST requests, whereas CRUD recommends use of a variety of HTTP methods.
TLDR
Two things:
- How can we use a module like connect-redis without using cookie-based sessions.
- How should we configure authentication information for maximum flexibility and interoperability?