Skip to content

Commit

Permalink
Removed hanging semi-colon syntax errors. Started to update README.
Browse files Browse the repository at this point in the history
  • Loading branch information
bnoguchi committed Apr 5, 2011
1 parent 10cb5b9 commit 16fd71a
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 253 deletions.
265 changes: 19 additions & 246 deletions README.md
Expand Up @@ -5,258 +5,31 @@ Authentication and authorization (password, facebook, & more) for your node.js C

`everyauth` is:

- *Modular* - We have you covered with Facebook and Twitter logins, basic login/password
support, and modules for beta invitation support and more.
- *Event-driven* - Applications each handle in their own unique way how they want to
respond to successful or failed authorizations, logins, and logouts. We expose these
events for you to empower you to handle these events exactly how you want to handle them.
- *Simple* - If you want to peek under the hood at its implementation, it is
straightforward to figure out what is going on.
- *Easily Configurable* - everyauth was built with powerful configuration needs in mind. One
of the problems I found with existing `connect` solutions was that it offered configurability
from options, but if you wanted to do anything more you had to dig into source and fork the
codebase. `everyauth` allows you to over-ride specific hooks so that you can configure it to
your auth needs.
- *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* - everyauth was built with powerful
configuration needs in mind. One of the problems I found
with existing `connect` solutions was that it offered
configurability from options, but if you wanted to do
anything more you had to dig into source and fork the
codebase. `everyauth` allows you to over-ride specific
hooks so that you can configure it to your auth needs.
- *Idiomatic* - The syntax for configuring and extending your authorization strategies are
idiomatic and chainable.
- *Step-driven*

## Installation
$ npm install everyauth

## Design
## Setting up Facebook Connect

To implement a minimally complete authorization strategy, applications need to

- Set up a complete set of routes exposing the one or more steps involved for a given
authorization strategy.
- Expose important events, general to authorization and specific to the given authorization
strategy, so the developer can define exactly how (s)he wants the app to handle each event.

We encapsulate each authorization strategy along with its routing and event logic
into everyauth modules.

The module system provides an easy entry point for developers to include not only a mix of
authorization strategies but also a mix of other desired, rich authorization features such as:

- Registration confirmation
- Password recovery
- Lockouts after X failed logins
- Timeouts to logout a user who has not been active
- Tracking login activity
- Allowing the user to have rememberable sessions

In addition to adding routes and exposing events at the auth strategy level, at a global level
`everyauth` adds helper methods to the incoming `request` to check the request auth status
(authorized, unauthorized, logged in, logged out) and to access the user associated with the
request.

The basic flow of events is:

1. Request authentication
2. Authentication strategy calls back to the app via
- `succeed`
- `fail`
3. If `succeed`, then the strategy calls back to the app with
credentials and possibly 3rd party user metadata (if configured, see below)
and possibly the found or created user (if configured, see below).
It is up to the app to decide what it wants to do with this information.
Likely, you will want to store this information in a session.
4. If `fail`, then the strategy calls back to the app with the error.

Within an OAuth submodule, there are additional events relative to
`succeed`.
fetchOAuthUserStep -> findOrCreateUserStep -> succeed

## General Auth Events
everyauth.on('login', function (user) {
});
everyauth.on('logout', function (user) {
});

## Facebook Auth
var everyauth = require('everyauth')
, connect = require('connect');

// Easy chainable interface
everyauth
.facebook
.appId('YOUR APP ID HERE')
.appSecret('YOUR APP SECRET HERE')
.myHostname('http://localhost:3000') // Note no trailing slash '/'
.scope('email'); // Configurable scope

// This anonymous function is invoked when Facebook OAuth succeeds
eveyauth.facebook.hook('succeed', function (req, res, user, credentials, fbUserMetadata) {
console.log(user); // The user retrieved from your database
console.log(credentials.accessToken);
console.log(credentials.refreshToken);
console.log(fbUserMetadata);

// You will want to save some of the function
// parameters to the session. How you want to do it
// is up to you.
if (!req.loggedIn) {
if (user) {
// The user may not be logged in from a prior auth strategy (e.g., Twitter)
res.writeHead(303, { Location: '/invite-facebook-friends' });
} else {
// The visitor has registered for the first time for your app via Facebook OAuth
res.writeHead(303, { Location: '/app-tutorial' });
}
} else {
// Or the user may already be logged in via another auth strategy
res.writeHead(303, { Location: '/invite-facebook-friends' });
}
res.end();
});

// This anonymous function is invoked when Facebook OAuth fails
eveyauth.facebook.hook('fail', function (req, res, err) {
// You can write err to a flash notice if you want
// or log it somewhere
console.warn(err);
res.writeHead(303, { Location: '/' });
res.end();
});

// [Unimplemented] This anonymous function gets invoked when a user revokes
// authorization for your app
everyauth.facebook.hook('revoke', function (req, res, err) {
});

var app = connect(
connect.bodyParser()
, connect.cookieParser()
, connect.session()
, everyauth.middleware() // everyauth gets inserted as connect middleware here
);

// You can introspect everyauth modules to see what routes they have added or will add
console.log(everyauth.facebook.routes);


### Facebook Hooks

### Configuring Routes

By default, the facebook module comes with the following routes:

- GET '/auth/facebook'
When you click on a "Login with Facebook" link, it will take you to
this uri. `everyauth` already has implemented the OAuth logic
that happens after you GET '/auth/facebook'. If you would like
to change the URI, you can do so via:

var handler = everyauth.fb.routes.get['/auth/facebook'];
delete everyauth.fb.routes.get['/auth/facebook'];
everyauth.fb.GET('/some/new/uri/for/fb', handler);

If you would like to change only the handler, you can do so via:

everyauth.fb.GET('/auth/facebook', function (req, res) {
// Your own custom logic here
});

If you would like to change the URI and the handler, then:
var everyauth = require('everyauth');

delete everyauth.fb.routes.get['/auth/facebook'];
everyauth.fb.GET('/some/new/uri/for/fb', function (req, res) {
});

- GET '/auth/facebook/callback'
This is the callback URI that you provide to Facebook OAuth. When
facebook is done with its OAuth logic, it redirects the user
back to this callback.

If you would like to change the URI, you can do so via:

everyauth.fb.callbackUri('/auth/facebook/new_callback');

// You can use introspection to remove routes to a module, too
everyauth.facebook.routes['/some/new/path'] = function () {
});

### Configuring Facebook Permissions Dynamically

It is recommended by Facebook that you only request
the permissions that you need at the time. So you may
start off requesting the default permissions and then
at a later point request more permissions. This implies
scope configuration that should vary dynamically based
on the current request session. Therefore, you can
specify a function that returns the appropriate scope
based on the current request:
everyauth.facebook.scope( function (req) {
if (req.session.additionalScopes)
return req.session.additionalScopes;
});

## Module Introspection

## OAuth Submodule Defaults

The Facebook module is a submodule of the OAuth module, which
comes with certain defaults. You can over-ride the following
defaults.
everyauth.facebook
.fetchOAuthUser(true);

Moreover, the Facebook module itself has the following
defaults, which you can also over-ride:
everyauth.facebook
.apiHost('https://graph.facebook.com')
.callbackUri('/auth/facebook/callback')
.GET('/auth/facebook', function (req, res) {
var fb = everyauth.facebook
, authorizeUri = fb.oauth.getAuthorizeUrl({redirect_uri: fb._myHostname + fb._callbackUri, scope: 'email'});
res.writeHead(303, { 'Location': authorizeUri });
res.end();
});

## Password Auth
everyauth.password.on('auth.succeed', function (req, res) {
if (!req.loggedIn) {
everyauth.facebook.emit('login', req, res, fbData);
} else {
res.redirect('/invite-facebook-friends');
}
});

everyauth.password.on('auth.fail', function (req, res, err) {
});

everyauth(app);

## Twitter Auth
everyauth
.twitter
.appId('')
.appSecret('');

everyauth.twitter.on('auth.succeed', function (req, res, accessToken) {
});

everyauth.twitter.on('auth.fail', function (req, res, err) {
});

everyauth.facebook.on('revoke', function (req, res, err) {
});

everyauth(app);

## Creating Your Own Custom Authentication Strategies
Creating your own authentication strategies is a straightforward process.
You only need to:

1. Instantiate a new auth submodule.
2. Define the routes required as part of your authentication strategy.
3. Specify the relevant hooks that correspond to the steps of and state changes for
the given authentication strategy.
4. Add any methods to the submodule configuration.

TODO Note differentiation between bound and descendant strategies when handling 'set.*' events

##

module.succeed -> everyauth.succeed
.myHostname('http://localhost:3000')
.appId('YOUR APP ID HERE')
.appSecret('YOUR APP SECRET HERE')
.findOrCreateUser( function (session, accessToken, fbUserMetadata) {
})
.redirectPath('/');
2 changes: 1 addition & 1 deletion index.js
@@ -1,4 +1,4 @@
var connect = require('connect');
var connect = require('connect')
, everyauth = module.exports = {};

// The connect middleware
Expand Down
4 changes: 3 additions & 1 deletion lib/everymodule.js
Expand Up @@ -14,6 +14,8 @@ function route (method) {

// TODO Add in check for missing step definitions
// from the set of step declarations
// TODO Add introspection to list incompletely defined steps
// TODO Add in ability for step to be optional
var everyModule = module.exports = {
definit: function (fn) {
// Remove any prior `init` that was assigned
Expand Down Expand Up @@ -56,7 +58,7 @@ var everyModule = module.exports = {
return this;
}
, step: function (name, opts) {
// TODO Use opts
// TODO Use opts (e.g., for ordering information {before: 'otherStepName'})
var steps = this._steps;
if (!steps[name]) {
steps[name] = {};
Expand Down
2 changes: 1 addition & 1 deletion lib/facebook.js
Expand Up @@ -2,8 +2,8 @@ var oauthModule = require('./oauth');

var fb = module.exports =
oauthModule.submodule('facebook')
.apiHost('https://graph.facebook.com')
.configurable('scope')
.apiHost('https://graph.facebook.com')
.entryPath('/auth/facebook')
.callbackPath('/auth/facebook/callback')
// Over-ride oauth's default getAuthUri to include Facebook's
Expand Down
10 changes: 8 additions & 2 deletions lib/oauth.js
Expand Up @@ -27,12 +27,13 @@ everyModule.submodule('oauth')
.accepts('code')
.promises('accessToken refreshToken')
.step('fetchOAuthUser')
.accepts('accessToken refreshToken')
.accepts('accessToken')
.promises('oauthUser')
.step('getSession')
.accepts('req')
.promises('session')
.step('findOrCreateUser')
//.optional()
.accepts('session accessToken oauthUser')
.promises('user')
.step('compile')
Expand Down Expand Up @@ -90,13 +91,18 @@ everyModule.submodule('oauth')

var _auth = session.auth || (session.auth = {})
, mod = _auth[this.name] || (_auth[this.name] = {});
_auth.loggedIn = true;
for (var k in auth) {
mod[k] = auth[k];
}
// this._super() ?
})
.sendResponse( function (res) {
res.redirect(this.redirectPath());
var redirectTo = this.redirectPath();
if (!redirectTo)
throw new Error('You must configure a redirectPath');
res.writeHead(303, redirectTo);
res.end();
})

// removeConfigurable
Expand Down
4 changes: 2 additions & 2 deletions lib/sequence.js
Expand Up @@ -45,8 +45,8 @@ MaterializedSequence.prototype = {
* @returns {Promise}
*/
, applyStep: function (step) {
var accepts = step.accepts;
, promises = step.promises;
var accepts = step.accepts
, promises = step.promises
// TODO step.block getter?
, block = step.module[step.name]();

Expand Down

0 comments on commit 16fd71a

Please sign in to comment.