#crafity-everyauth

Authentication and authorization (password, facebook, & more) for your node.js Connect and Express apps.
There is a NodeTuts screencast of everyauth here
So far, crafity-everyauth
enables you to login via:
crafity-everyauth
is:
- Modular - We have you covered with Facebook and Twitter
OAuth logins, basic login/password support, and modules
coming soon for beta invitation support and more.
- Easily Configurable - crafity-everyauth was built with powerful
configuration needs in mind. Configure an authorization strategy
in a straightforward, easy-to-read & easy-to-write approach,
with as much granularity as you want over the steps and
logic of your authorization strategy.
- Idiomatic - The syntax for configuring and extending your authorization strategies are
idiomatic and chainable.
Installation
$ npm install crafity-everyauth
Quick Start
Using crafity-everyauth comes down to just 2 simple steps if using Connect
or 3 simple steps if using Express:
-
Choose and Configure Auth Strategies - Find the authentication strategy
you desire in one of the sections below. Follow the configuration
instructions.
-
Add the Middleware to Connect
var everyauth = require('crafity-everyauth');
var connect = require('connect');
var app = connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'mr ripley'})
, everyauth.middleware()
, connect.router(routes)
);
-
Add View Helpers to Express
everyauth.helpExpress(app);
app.listen(3000);
For more about what view helpers crafity-everyauth
adds to your app, see the section
titled "Express Helpers" near the bottom of this README.
Example Application
There is an example application at ./example
To run it:
$ cd example
$ node server.js
Important - Some OAuth Providers do not allow callbacks to localhost, so you will need to create a localhost
alias called local.host
. Make sure you set up your /etc/hosts so that 127.0.0.1 is also
associated with 'local.host'. So inside your /etc/hosts file, one of the lines will look like:
127.0.0.1 localhost local.host
Then point your browser to http://local.host:3000
Tests
First, spin up the example server (See last section "Example Application").
Then,
$ make test
Logging Out
If you integrate crafity-everyauth
with connect
, then crafity-everyauth
automatically
sets up a logoutPath
at GET
/logout
for your app. It also
sets a default handler for your logout route that clears your session
of auth information and redirects them to '/'.
To over-write the logout path:
everyauth.everymodule.logoutPath('/bye');
To over-write the logout redirect path:
everyauth.everymodule.logoutRedirectPath('/navigate/to/after/logout');
To over-write the logout handler:
everyauth.everymodule.handleLogout( function (req, res) {
req.logout();
res.writeHead(303, { 'Location': this.logoutRedirectPath() });
res.end();
});
Setting up Facebook Connect
var everyauth = require('crafity-everyauth')
, connect = require('connect');
everyauth.facebook
.appId('YOUR APP ID HERE')
.appSecret('YOUR APP SECRET HERE')
.handleAuthCallbackError( function (req, res) {
})
.findOrCreateUser( function (session, accessToken, accessTokExtra, fbUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
everyauth.facebook
.entryPath('/auth/facebook')
.callbackPath('/auth/facebook/callback')
.scope('email')
If you want to see what the current value of a
configured parameter is, you can do so via:
everyauth.facebook.scope();
everyauth.facebook.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
everyauth.facebook.configurable();
Dynamic Facebook Connect Scope
Facebook provides many different
permissions
for which your app can ask your user. This is bundled up in the scope
query
paremter sent with the oauth request to Facebook. While your app may require
several different permissions from Facebook, Facebook recommends that you only
ask for these permissions incrementally, as you need them. For example, you might
want to only ask for the "email" scope upon registration. At the same time, for
another user, you may want to ask for "user_status" permissions because they
have progressed further along in your application.
crafity-everyauth
enables you to specify the "scope" dynamically with a second
variation of the configurable scope
. In addition to the first variation
that looks like:
everyauth.facebook
.scope('email,user_status');
you can have greater dynamic control over "scope" via the second variation of scope
:
everyauth.facebook
.scope( function (req, res) {
var session = req.session;
switch (session.userPhase) {
case 'registration':
return 'email';
case 'share-media':
return 'email,user_status';
}
});
var everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.twitter
.consumerKey('YOUR CONSUMER ID HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (session, accessToken, accessTokenSecret, twitterUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
Important - Some developers forget to do the following, and it causes them to have issues with crafity-everyauth
.
Please make sure to do the following: When you set up your app at http://dev.twitter.com/, make sure that your callback url is set up to
include that path '/auth/twitter/callback/'. In general, when dealing with OAuth or OAuth2 modules
provided by crafity-everyauth
, the default callback path is always set up to follow the pattern
'/auth/#{moduleName}/callback', so just ensure that you configure your OAuth settings accordingly with
the OAuth provider -- in this case, the "Edit Application Settings" section for your app at http://dev.twitter.com.
Alternatively, you can specify the callback url at the application level by configuring callbackPath
(which
has a default configuration of "/auth/twitter/callback"):
crafity-everyauth.twitter
.consumerKey('YOUR CONSUMER ID HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.callbackPath('/custom/twitter/callback/path')
.findOrCreateUser( function (session, accessToken, accessTokenSecret, twitterUserMetadata) {
})
.redirectPath('/');
So if your hostname is example.com
, then this configuration will over-ride the dev.twitter.com
callback url configuration.
Instead, Twitter will redirect back to example.com/custom/twitter/callback/path
in the example just given above.
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.twitter
.entryPath('/auth/twitter')
.callbackPath('/auth/twitter/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.twitter.callbackPath();
crafity-everyauth.twitter.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.twitter.configurable();
Setting up Password Authentication
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.password
.getLoginPath('/login')
.postLoginPath('/login')
.loginView('a string of html; OR the name of the jade/etc-view-engine view')
.authenticate( function (login, password) {
})
.loginSuccessRedirect('/')
.getRegisterPath('/register')
.postRegisterPath('/register')
.registerView('a string of html; OR the name of the jade/etc-view-engine view')
.validateRegistration( function (newUserAttributes) {
})
.registerUser( function (newUserAttributes) {
})
.registerSuccessRedirect('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.password
.loginFormFieldName('login')
.passwordFormFieldName('password')
.loginLayout('custom_login_layout')
.registerLayout('custom reg_layout')
.loginLocals(fn);
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.password.loginFormFieldName();
crafity-everyauth.password.passwordFormFieldName();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.password.configurable();
Sometimes your registration will ask for more information from the user besides the login and password.
For this particular scenario, you can configure the optional step, extractExtraRegistrationParams
.
crafity-everyauth.password.extractExtraRegistrationParams( function (req) {
return {
phone: req.body.phone
, name: {
first: req.body.first_name
, last: req.body.last_name
}
};
});
Password Recipe 2: Logging in with email or phone number
By default, crafity-everyauth
uses the field and user key name login
during the
registration and login process.
Sometimes, you want to use email
or phone
instead of login
. Moreover,
you also want to validate email
and phone
fields upon registration.
crafity-everyauth
provides an easy way to do this:
crafity-everyauth.password.loginWith('email');
crafity-everyauth.password.loginWith('phone');
With simple login configuration like this, you get email (or phone) validation
in addition to renaming of the form field and user key corresponding to what
otherwise would typically be referred to as 'login'.
Password Recipe 3: Adding additional view local variables to login and registration views
If you are using express
, you are able to pass variables from your app
context to your view context via local variables. crafity-everyauth
provides
several convenience local vars for your views, but sometimes you will want
to augment this set of local vars with additional locals.
So crafity-everyauth
also provides a mechanism for you to do so via the following
configurables:
crafity-everyauth.password.loginLocals(...);
crafity-everyauth.password.registerLocals(...);
loginLocals
and registerLocals
configuration have symmetrical APIs, so I
will only cover loginLocals
here to illustrate how to use both.
You can configure this parameter in one of 3 ways. Why 3? Because there are 3 types of ways that you can retrieve your locals.
-
Static local vars that never change values:
```javascript
crafity-everyauth.password.loginLocals({
title: 'Login'
});
```
-
Dynamic synchronous local vars that depend on the incoming request, but whose values are retrieved synchronously
```javascript
crafity-everyauth.password.loginLocals( function (req, res) {
var sess = req.session;
return {
isReturning: sess.isReturning
};
});
```
-
Dynamic asynchronous local vars
```javascript
crafity-everyauth.password.loginLocals( function (req, res, done) {
asyncCall( function ( err, data) {
if (err) return done(err);
done(null, {
title: il8n.titleInLanguage('Login Page', il8n.language(data.geo))
});
});
});
```
Password Recipe 4: Customize Your Registration Validation
By default, crafity-everyauth.password
automatically
- validates that the login (or email or phone, depending on what you authenticate with -- see Password Recipe 2) is present in the login http request,
- validates that the password is present
- validates that an email login is a correctly formatted email
- validates that a phone login is a valid phone number
If any of these validations fail, then the appropriate errors are generated and accessible to you in your view via the errors
view local variable.
If you want to add additional validations beyond this, you can do so by configuring the step, validateRegistration
:
crafity-everyauth.password
.validateRegistration( function (newUserAttributes, baseErrors) {
var moreErrors = validateUser( newUserAttributes );
if (moreErrors.length) baseErrors.push.apply(baseErrors, moreErrors);
return baseErrors;
});
Setting up GitHub OAuth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.github
.appId('YOUR CLIENT ID HERE')
.appSecret('YOUR CLIENT SECRET HERE')
.findOrCreateUser( function (session, accessToken, , accessTokenExtra, githubUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.github
.entryPath('/auth/github')
.callbackPath('/auth/github/callback')
.scope('repo');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.github.scope();
crafity-everyauth.github.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.github.configurable();
Setting up Instagram OAuth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.instagram
.appId('YOUR CLIENT ID HERE')
.appSecret('YOUR CLIENT SECRET HERE')
.findOrCreateUser( function (session, accessToken, accessTokenExtra, instagramUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.instagram
.entryPath('/auth/instagram')
.callbackPath('/auth/instagram/callback')
.scope('basic')
.display(undefined);
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.instagram.callbackPath();
crafity-everyauth.instagram.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.instagram.configurable();
Setting up Foursquare OAuth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.foursquare
.appId('YOUR CLIENT ID HERE')
.appSecret('YOUR CLIENT SECRET HERE')
.findOrCreateUser( function (session, accessToken, accessTokenExtra, foursquareUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.foursquare
.entryPath('/auth/foursquare')
.callbackPath('/auth/foursquare/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.foursquare.callbackPath();
crafity-everyauth.foursquare.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.foursquare.configurable();
Setting up LinkedIn OAuth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.linkedin
.consumerKey('YOUR CONSUMER ID HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (session, accessToken, accessTokenSecret, linkedinUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.linkedin
.entryPath('/auth/linkedin')
.callbackPath('/auth/linkedin/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.linkedin.callbackPath();
crafity-everyauth.linkedin.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.linkedin.configurable();
Setting up Google OAuth2
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.google
.appId('YOUR CLIENT ID HERE')
.appSecret('YOUR CLIENT SECRET HERE')
.scope('https://www.google.com/m8/feeds')
.handleAuthCallbackError( function (req, res) {
})
.findOrCreateUser( function (session, accessToken, accessTokenExtra, googleUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.google
.entryPath('/auth/google')
.callbackPath('/auth/google/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.google.scope();
crafity-everyauth.google.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.google.configurable();
Setting up Gowalla OAuth2
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.gowalla
.appId('YOUR CLIENT ID HERE')
.appSecret('YOUR CLIENT SECRET HERE')
.handleAuthCallbackError( function (req, res) {
})
.findOrCreateUser( function (session, accessToken, accessTokenExtra, gowallaUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.gowalla
.entryPath('/auth/gowalla')
.callbackPath('/auth/gowalla/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.gowalla.scope();
crafity-everyauth.gowalla.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.gowalla.configurable();
Setting up 37signals (Basecamp, Highrise, Backpack, Campfire) OAuth2
First, register an app at integrate.37signals.com.
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth['37signals']
.appId('YOUR CLIENT ID HERE')
.appSecret('YOUR CLIENT SECRET HERE')
.handleAuthCallbackError( function (req, res) {
})
.findOrCreateUser( function (session, accessToken, accessTokenExtra, _37signalsUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth['37signals']
.entryPath('/auth/37signals')
.callbackPath('/auth/37signals/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth['37signals'].entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth['37signals'].configurable();
Setting up Yahoo OAuth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.yahoo
.consumerKey('YOUR CONSUMER KEY HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (session, accessToken, accessTokenSecret, yahooUserMetadata) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.yahoo
.entryPath('/auth/yahoo')
.callbackPath('/auth/yahoo/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.yahoo.callbackPath();
crafity-everyauth.yahoo.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.yahoo.configurable();
Setting up Readability OAuth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.readability
.consumerKey('YOUR CONSUMER KEY HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (sess, accessToken, accessSecret, reader) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.readability
.entryPath('/auth/readability')
.callbackPath('/auth/readability/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.readability.callbackPath();
crafity-everyauth.readability.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.readability.configurable();
Setting up Dropbox OAuth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.dropbox
.consumerKey('YOUR CONSUMER KEY HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (sess, accessToken, accessSecret, user) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.dropbox
.entryPath('/auth/dropbox')
.callbackPath('/auth/dropbox/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.dropbox.callbackPath();
crafity-everyauth.dropbox.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.dropbox.configurable();
Setting up Justin.tv OAuth
Sign up for a Justin.tv account and activate it as a developer account to get your consumer key and secret.
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.justintv
.consumerKey('YOUR CONSUMER KEY HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (sess, accessToken, accessSecret, justintvUser) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
The justintvUser
parameter in the .findOrCreateUser()
function above returns the account/whoami
API call
Justin.tv API Wiki - Account/whoami
{
"image_url_huge": "http:\/\/static-cdn.justin.tv\/jtv_user_pictures\/justin-320x240-4.jpg",
"profile_header_border_color": null,
"favorite_quotes": "I love Justin.tv",
"sex": "Male",
"image_url_large": "http:\/\/static-cdn.justin.tv\/jtv_user_pictures\/justin-125x94-4.jpg",
"profile_about": "Check out my website:\n\nwww.justin.tv\n",
"profile_background_color": null,
"image_url_medium": "http:\/\/static-cdn.justin.tv\/jtv_user_pictures\/justin-75x56-4.jpg",
"id": 1698,
"broadcaster": true,
"profile_url": "http:\/\/www.justin.tv\/justin\/profile",
"profile_link_color": null,
"image_url_small": "http:\/\/static-cdn.justin.tv\/jtv_user_pictures\/justin-50x37-4.jpg",
"profile_header_text_color": null,
"name": "The JUST UN",
"image_url_tiny": "http:\/\/static-cdn.justin.tv\/jtv_user_pictures\/justin-33x25-4.jpg",
"login": "justin",
"profile_header_bg_color": null,
"location": "San Francisco"
}
You can also configure more parameters (most are set to defaults) via the same chainable API:
crafity-everyauth.justintv
.entryPath('/auth/justintv')
.callbackPath('/auth/justintv/callback');
If you want to see what the current value of a configured parameter is, you can do so via:
crafity-everyauth.justintv.callbackPath();
crafity-everyauth.justintv.entryPath();
To see all parameters that are configurable, the following will return an object whose parameter name keys map to description values:
crafity-everyauth.justintv.configurable();
Setting up Vimeo OAuth
You will first need to sign up for a developer application to get the consumer key and secret.
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.vimeo
.consumerKey('YOUR CONSUMER KEY HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (sess, accessToken, accessSecret, user) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.vimeo
.entryPath('/auth/vimeo')
.callbackPath('/auth/vimeo/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.vimeo.callbackPath();
crafity-everyauth.vimeo.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.vimeo.configurable();
Setting up Tumblr OAuth (1.a)
You will first need to register an app to get the consumer key and secret.
During registration of your new app, enter a "Default callback URL" of "http://:/auth/tumblr/callback".
Once you register your app, copy down your "OAuth Consumer Key" and "Secret Key" and proceed below.
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.tumblr
.consumerKey('YOUR CONSUMER KEY HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.findOrCreateUser( function (sess, accessToken, accessSecret, user) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.tumblr
.entryPath('/auth/tumblr')
.callbackPath('/auth/tumblr/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.tumblr.callbackPath();
crafity-everyauth.tumblr.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.tumblr.configurable();
Setting up OpenID protocol
OpenID protocol allows you to use an openid auth request. You can read more information about it here http://openid.net/
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.openid
.myHostname('http://localhost:3000')
.simpleRegistration({
"nickname" : true
, "email" : true
, "fullname" : true
, "dob" : true
, "gender" : true
, "postcode" : true
, "country" : true
, "language" : true
, "timezone" : true
})
.attributeExchange({
"http://axschema.org/contact/email" : "required"
, "http://axschema.org/namePerson/friendly" : "required"
, "http://axschema.org/namePerson" : "required"
, "http://axschema.org/namePerson/first" : "required"
, "http://axschema.org/contact/country/home": "required"
, "http://axschema.org/media/image/default" : "required"
, "http://axschema.org/x/media/signature" : "required"
})
.openidURLField('openid_identifier');
.findOrCreateUser( function(session, openIdUserAttributes) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
Setting up Google OpenID+OAuth Hybrid protocol
OpenID+OAuth Hybrid protocol allows you to combine an openid auth request with a oauth access request. You can read more information about it here http://code.google.com/apis/accounts/docs/OpenID.html
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.googlehybrid
.consumerKey('YOUR CONSUMER ID HERE')
.consumerSecret('YOUR CONSUMER SECRET HERE')
.scope(['GOOGLE API SCOPE','GOOGLE API SCOPE'])
.findOrCreateUser( function(session, userAttributes) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
Setting up Box.net Auth
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.box
.apiKey('YOUR API KEY')
.findOrCreateUser( function (sess, authToken, boxUser) {
})
.redirectPath('/');
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
You can also configure more parameters (most are set to defaults) via
the same chainable API:
crafity-everyauth.box
.entryPath('/auth/box')
.callbackPath('/auth/box/callback');
If you want to see what the current value of a
configured parameter is, you can do so via:
crafity-everyauth.box.callbackPath();
crafity-everyauth.box.entryPath();
To see all parameters that are configurable, the following will return an
object whose parameter name keys map to description values:
crafity-everyauth.box.configurable();
Setting up LDAP
The LDAP module is still in development. Do not use it in production yet.
Install OpenLDAP client libraries:
$ apt-get install slapd ldap-utils
Install node-ldapauth:
var crafity-everyauth = require('crafity-everyauth')
, connect = require('connect');
crafity-everyauth.ldap
.host('your.ldap.host')
.port(389)
.getLoginPath(...)
.postLoginPath(...)
.loginView(...)
.loginSuccessRedirect(...);
var routes = function (app) {
};
connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session({secret: 'whodunnit'})
, crafity-everyauth.middleware()
, connect.router(routes);
).listen(3000);
Accessing the User
If you are using express
or connect
, then crafity-everyauth
provides an easy way to access the user as:
req.user
from your app server
crafity-everyauth.user
via the crafity-everyauth
helper accessible from your express
views.
user
as a helper accessible from your express
views
To access the user, configure crafity-everyauth.everymodule.findUserById
.
For example, using mongoose:
crafity-everyauth.everymodule.findUserById( function (userId, callback) {
User.findById(userId, callback);
});
Once you have configured this method, you now have access to the user object
that was fetched anywhere in your server app code as req.user
. For instance:
var app = require('express').createServer()
app.get('/', function (req, res) {
console.log(req.user);
res.render('home');
});
Moreover, you can access the user in your views as crafity-everyauth.user
or as user
.
//- Inside ./views/home.jade
span.user-id= crafity-everyauth.user.name
#user-id= user.id
Express Helpers
If you are using express, crafity-everyauth comes with some useful dynamic helpers.
To enable them:
var express = require('express')
, crafity-everyauth = require('crafity-everyauth')
, app = express.createServer();
crafity-everyauth.helpExpress(app);
Then, from within your views, you will have access to the following helpers methods
attached to the helper, crafity-everyauth
:
crafity-everyauth.loggedIn
crafity-everyauth.user
- the User document associated with the session
crafity-everyauth.facebook
- The is equivalent to what is stored at req.session.auth.facebook
,
so you can do things like ...
crafity-everyauth.facebook.user
- returns the user json provided from the OAuth provider.
crafity-everyauth.facebook.accessToken
- returns the access_token provided from the OAuth provider
for authorized API calls on behalf of the user.
- And you also get this pattern for other modules - e.g.,
crafity-everyauth.twitter.user
,
crafity-everyauth.github.user
, etc.
You also get access to the view helper
user
- the same as crafity-everyauth.user
above
As an example of how you would use these, consider the following ./views/user.jade
jade template:
.user-id
.label User Id
.value #{user.id}
.facebook-id
.label User Facebook Id
.value #{crafity-everyauth.facebook.user.id}
crafity-everyauth
also provides convenience methods on the ServerRequest
instance req
.
From any scope that has access to req
, you get the following convenience getters and methods:
req.loggedIn
- a Boolean getter that tells you if the request is by a logged in user
req.user
- the User document associated with the session
req.logout()
- clears the sesion of your auth data
Configuring a Module
crafity-everyauth was built with powerful configuration needs in mind.
Every module comes with a set of parameters that you can configure
directly. To see a list of those parameters on a per module basis,
with descriptions about what they do, enter the following into the
node REPL (to access the REPL, just type node
at the command line)
> var ea = require('crafity-everyauth');
> ea.facebook.configurable();
For example, you will see that one of the configuration parameters is
moduleTimeout
, which is described to be how long to wait per step before timing out and invoking any timeout callbacks
Every configuration parameter corresponds to a method of the same name
on the auth module under consideration (i.e., in this case
ea.facebook
). To create or over-write that parameter, just
call that method with the new value as the argument:
ea.facebook
.moduleTimeout( 4000 );
Configuration parameters can be scalars. But they can be anything. For
example, they can also be functions, too. The facebook module has a
configurable step named findOrCreateUser
that is described as
"STEP FN [findOrCreateUser] function encapsulating the logic for the step
fetchOAuthUser
.". What this means is that this configures the
function (i.e., "FN") that encapsulates the logic of this step.
ea.facebook
.findOrCreateUser( function (session, accessToken, extra, oauthUser) {
});
How do we know what arguments the function takes?
We elaborate more about step function configuration in our
Introspection
section below.
Introspection
crafity-everyauth provides convenient methods and getters for finding out
about any module.
Show all configurable parameters with their descriptions:
crafity-everyauth.facebook.configurable();
Show the value of a single configurable parameter:
crafity-everyauth.facebook.callbackPath();
Show the declared routes (pretty printed):
crafity-everyauth.facebook.routes;
Show the steps initiated by a given route:
crafity-everyauth.facebook.route.get.entryPath.steps;
crafity-everyauth.facebook.route.get.callbackPath.steps;
Sometimes you need to set up additional steps for a given auth
module, by defining that step in your app. For example, the
set of steps triggered when someone requests the facebook
module's callbackPath
contains a step that you must define
in your app. To see what that step is, you can introspect
the callbackPath
route with the facebook module.
crafity-everyauth.facebook.route.get.callbackPath.steps.incomplete;
This tells you that you must define the function that defines the
logic for the findOrCreateUser
step. To see what the function
signature looks like for this step:
var matchingStep =
crafity-everyauth.facebook.route.get.callbackPath.steps.filter( function (step) {
return step.name === 'findOrCreateUser';
})[0];
This tells you that the function should take the following 4 arguments:
function (session, accessToken, extra, oauthUser) {
...
}
And that the function should return a user
that is a user object or
a Promise that promises a user object.
function (session, accessToken, extra, oauthUser) {
...
return { id: 'some user id', username: 'some user name' };
}
function (session, accessToken, extra, oauthUser) {
var promise = this.Promise();
asyncFindUser( function (err, user) {
if (err) return promise.fail(err);
promise.fulfill(user);
});
return promise;
}
You add this function as the block for the step findOrCreateUser
just like
you configure any other configurable parameter in your auth module:
crafity-everyauth.facebook
.findOrCreateUser( function (session, accessToken, extra, oauthUser) {
});
There are also several other introspection tools at your disposal:
For example, to show the submodules of an auth module by name:
crafity-everyauth.oauth2.submodules;
Other introspection tools to describe (explanations coming soon):
Debugging
Debugging - Logging Module Steps
To turn on debugging:
crafity-everyauth.debug = true;
Each crafity-everyauth auth strategy module is composed of steps. As each step begins and ends, crafity-everyauth will print out to the console the beginning and end of each step. So by turning on the debug flag, you get insight into what step crafity-everyauth is executing at any time.
Debugging - Configuring Error Handling
By default, all modules handle errors by throwing them. That said, crafity-everyauth
allows
you to over-ride this behavior.
You can configure error handling at the module and step level. To handle all
errors in the same manner across all auth modules that you use, do the following.
crafity-everyauth.everymodule.moduleErrback( function (err) {
});
You can also configure your error handling on a per module basis. So, for example, if
you want to handle errors during the Facebook module differently than in other modules:
crafity-everyauth.facebook.moduleErrback( function (err) {
});
Debugging - Setting Timeouts
By default, every module has 10 seconds to complete each step. If a step takes longer than 10 seconds to complete, then crafity-everyauth will pass a timeout error to your configured error handler (see section "Configure Error Handling" above).
If you would like to increase or decrease the timeout period across all modules, you can do so via:
crafity-everyauth.everymodule.moduleTimeout(2000);
You can eliminate the timeout altogether by configuring your timeouts to -1:
crafity-everyauth.everymodule.moduleTimeout(-1);
You can also configure the timeout period on a per module basis. For example, the following will result in the facebook module having 3 seconds to complete each step before timing out; all other modules will have the default 10 seconds per step before timing out.
crafity-everyauth.facebook.moduleTimeout(3000);
Modules and Projects that use crafity-everyauth
Currently, the following module uses crafity-everyauth. If you are using crafity-everyauth
in a project, app, or module, get in touch to get added to the list below:
- mongoose-auth Authorization plugin
for use with the node.js MongoDB orm.
Author
Brian Noguchi
Credits
Thanks to the following contributors for the following modules:
MIT License
Copyright (c) 2011 by Brian Noguchi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.