Rational and Screencast for Drawbridge.js
Drawbridge.js is a Node.js module for adding authentication, waiting lists and account invitations to an Express.js application. Drawbridge stores all its data in a Redis database obviating migrations or slow queries. Drawbridge.js includes an admin panel to view those on the waiting list, sent invitations and app users.
The goal of Drawbridge is to create a password authentication module that requires as few lines of code to add authentication to your app. While drawbridge creates a views and email templates you are free to change their content - only the names of the templates and views need to stay the same.
The Good Drawbridge makes it extremely easy to add authentication to your express.js app. Drawbridge uses bcrypt to hash passwords and Redis to persist user data.
The Bad Drawbridge still needs a lot more testing, and should be considered an alpha product.
npm install drawbridge.js -g
In the root of your express application's directory, from the terminal:
drawbridge build
The drawbridge build
shell command will create a number of views, email templates, a Terms of Service text file, and a configuration file (drawbridge.config.json). It is important that you modify the values on the configuration file before you get started - if you do not, emails will not be sent. See the drawbridge.config.json section below for more details. Also note that the express app was created using the --sessions
switch, to add support for sessions.
var express = require('express')
, routes = require('./routes')
, drawbridge = require('drawbridge');
var app = module.exports = express.createServer();
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({ secret: 'your secret here' }));
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.use(express.logger());
});
// start drawbridge using .up()
drawbridge = drawbridge.up( app );
// provide a function to be called after a user login
drawbridge.afterLogin( function( response, user ){
response.redirect('/' + user.screenName );
});
// A route with authentication
app.get('/:screenName', drawbridge.authenticateUser, function(req, res){
res.json( drawbridge.currentUser( req ) )
})
// Routes
app.get('/', routes.index);
app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
Drawbridge provides all the basic password authentication services and views. It provides:
- login view and routes
- logout view and route
- password reset view and routes
- password reset email templates, with link for resetting password
- registration view and routes, with email confirmation template
- functions for adding authentication to a given route
- An optional Terms of Service that will be shown to the potential user at registration
Many new applications start with a sign-up form that put potential users on a waiting list. Drawbridge.js provides the code for both the sign-up form and the functionality to store the sign-up data, and notify the potential user, via email, that the sign-up was successful. To add the sign-up form to your site see the "View Partial" section below.
The app's admin can then use Drawbridge.js's admin view to manually invite each user ( if there is interest inviting users could be automated ). Once a user is invited, they are sent an email with a registration link that includes a unique token. After a user register they receive an email with a confirmation email. Once they've confirmed their account they're logged in.
Drawbridge.js can currently send emails using postmark or nodemailer. To use either service the drawbridge.config.json must be modified. Adding adapters for other emailing methods should be extremely easy, see lib/email.js
and the files within lib/email
.
To use nodemailer:
"email" : {
"module" : "nodemailer",
"service" : "Gmail",
"auth" : {
"user" : "[email protected]",
"pass" : "password"
}
},
To use postmark:
IMPORTANT: To use postmark the "from" email addresses in the drawbridge.config.json file have to be registered as "Sender Signatures" within your Postmark.com account.
"email" : {
"module" : "postmark",
"APIKEY" : "********-****-****-****-************"
},
The drawbridge.config.json files defines all of the basic settings an configuration for drawbridge. It defines all of the "subject" and "from" values for each email type that drawbridge sends. It defines the email and database modules that it uses ( right now the only database is Redis ). It also defines a super user account that is created when drawbridge is instantiated.
The drawbridge.config.json file also has a flag for whether your app will include a waitlist ("waitlist" : true - within the "signups" sub object). If the waitlist flag is true only those invited will be able to register.
Drawbridge.js includes a view partial for accepting signups, for your apps waiting list. The partial also includes some javascript to submit the form's contents asynchronously to your app. When the submission is complete the form disapears.
!= partial('drawbridge/signup/signup.jade',{})
- response express response object
- user The currently logged in user object
.afterLogin
is called directly after a user 1) logins, 2) confirms registration and 3) resets their password. If this function is not called, drawbridge will redirect to the root url.
drawbridge.afterLogin( function( response, user ){
response.redirect( '/users/' + user.screenName );
});
- request express request object
- response express response object
- next express next function
.authenticateUser()
is used to add authenticate to a route.
app.get( '/account/:screenName', [ drawbridge.authenticateUser ], function( req, res){
var screenName = req.params.screenName;
res.render('account', { title: 'Account', screenName : screenName });
});
- request express request object
- response express response object
- next express next function
.authenticateSuperUser()
is used to authenticate users with the superUser
flag for a route.
app.get( '/admin/settings', [ drawbridge.authenticateSuperUser ], function( req, res){
var settings = database.getSettings();
res.render('admin/settings', { title: 'Settings', settings : settings });
});
- request express request object
.currentUser()
returns the logged in user associated with the current request.
app.get( '/getuser.json', [ drawbridge.authenticateUser ], function( req, res ){
res.json( drawbrdige.getCurrentUser( req ) );
});
- object specifies either an email, or a screenName
- function is called after .getUser() is complete
.getUser()
takes an object that specifies either an email, or a screenName, and through the callback function returns the matching user. If there is no matching user null
is returned.
var aUser;
drawbridge.getUser( { email: '[email protected]' }, function( error, user ){
if( error ){
throw "An error!!!"
}else{
aUser = user;
}
});
- email a user's email address
- object contains all the key-values that will be changed for the user
.changeUsersAttributes()
will modify the value for keys that already exist for a user. If a key in object does not exist, the key and value will be added to the user.
var obj = {
firstName : "Ringo",
lastName : "Star"
};
drawbridge.changeUsersAttributes( '[email protected]', obj, function( error, results ){
if( error ){
throw "Oh no!";
}else{
console.log( "Success" );
}
});
- function is a callback function that takes two parameters, an error, and an array with the results
.getUsers()
takes a callback function and returns an array with all the users in the database.
app.get('/numUsers.json', function( req, res ){
drawbrdige.getUsers( function( error, users ){
res.json( users.length );
});
});
- function is a callback function that takes two parameters, an error, and an array with results.
.getWaitlist()
takes a callback function and returns an array of objects, each object representing a person on the waiting list.
app.get('/waitinglist', function( req, res ){
drawbrdige.getWaitlist( function( error, users ){
res.render('waitlist', { title : "Waitlist", waitlist : users });
});
});
- function is a callback function that takes two parameters, an error, and an arrow with results.
.getInvited()
takes a callback function and returns an array of objects, each object representing a person who has been invited.
app.get('/invited', function( req, res ){
drawbridge.getInvited( function( error, users ){
res.render('invited', { title : "Invited", invited : users });
});
})
- Liam Kaufman ( https://github.com/liamks )
MIT License. Copyright 2012 Liam Kaufman. http://liamkaufman.com