Normalmente en nuestras aplicaciones web llega un momento en el que necesitamos implementar un sistema de registro y autenticación de usuarios.
Podemos programarlo desde cero, pero llega a ser una tarea bastante tediosa, tenemos que tener en cuenta sesiones, privacidad, encriptación de contraseñas, etc,... Si ha esto le sumamos la implementación de un registro con cuenta de Facebook o Twitter como en el acceso a los cursos de Mejorando.la, la cosa se complica bastante.
Para implementar un registro y autenticación de usuarios en Node.js, tenemos la librería Passport. A continuación veremos como implementarlo.

Necesitamos tener Node.js y MongoDB instalados en nuestro entorno. La instalación es diferente según el sistema operativo. Googlea sobre ello, encontrarás información de sobra

Configurando nuestro entorno
Seguidamente vamos a crear el esqueleto de una aplicación Node con el framework Express
Código :
$ npm install -g express $ express login-social $ cd login-social $ npm install
A continuación instalamos las dependencias que vamos a emplear en la aplicación, lo hacemos con el flag `--save` para guardarlos en el `package.json`
Código :
$ npm install --save mongoose $ npm install --save passport $ npm install --save passport-twitter $ npm install --save passport-facebook
Vamos a crear un modelo para guardar los datos del usuario. El siguiente código corresponde al archivo models/user.js:
Código :
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var UserSchema = new Schema({ name: String, provider: String, provider_id: {type: String, unique: true}, photo: String, createdAt: {type: Date, default: Date.now} }); var User = mongoose.model('User', UserSchema);
Dando de alta nuestra aplicación en redes sociales
Antes de configuar Passport, vamos a crear una aplicación en Facebook y otra en Twitter para obtener sus claves de API (Key y Secret) y así poder usar esos proveedores en nuestras estrategias de registro.
Registro en Twitter: http://dev.twitter.com
Registro en Facebook: http://developers.facebook.com






Estas claves las vamos a indicar en un fichero de configuración ya que es una buena práctica es mantener las API Keys separadas del código fuente que subimos al repositorio, en un archivo `config.js` que luego importamos desde donde lo necesitemos:
Código :
var config = { twitter: { key: ‘TWITTER_API_KEY’, secret: ‘TWITTER_API_SECRET’ }, facebook: { id: ‘FACEBOOK_APP_ID’, secret: ‘FACEBOOK_APP_SECRET’ } }; module.exports = config;
Usando passport.js
Lo siguiente que debemos hacer es configurar Passport, para ello hacemos uso de las funciones `serializeUser` y `deserializeUser` hacemos que el objeto que representa al usuario se almacene en la sesión. Las estrategias `TwitterStrategy` y `FacebookStrategy` utilizamos las estrategias de autenticación que nos proporciona Passport. Necesitamos las claves que hemos indicado antes:
passport.js
Código :
var mongoose = require('mongoose'); var User = mongoose.model('User'); var TwitterStrategy = require('passport-twitter').Strategy; var FacebookStrategy = require('passport-facebook').Strategy; var config = require('./config); module.exports = function(passport) { passport.serializeUser(function(user, done) { done(null, user); }); passport.deserializeUser(function(obj, done) { done(null, obj); }); passport.use(new TwitterStrategy({ consumerKey: config.twitter.key, consumerSecret: config.twitter.secret, callbackURL: '/auth/twitter/callback' }, function(accessToken, refreshToken, profile, done) { User.findOne({provider_id: profile.id}, function(err, user) { if(err) throw(err); if(!err && user!= null) return done(null, user); var user = new User({ provider_id: profile.id, provider: profile.provider, name: profile.displayName, photo: profile.photos[0].value }); user.save(function(err) { if(err) throw err; done(null, user); }); }); })); passport.use(new FacebookStrategy({ clientID: config.facebook.id, clientSecret: config.facebook.secret, callbackURL: '/auth/twitter/callback' }, function(accessToken, refreshToken, profile, done) { User.findOne({provider_id: profile.id}, function(err, user) { if(err) throw(err); if(!err && user!= null) return done(null, user); var user = new User({ provider_id: profile.id, provider: profile.provider, name: profile.displayName, photo: profile.photos[0].value }); user.save(function(err) { if(err) throw err; done(null, user); }); }); }));
Ya podemos configurar el server express con los middlewares `app.js`:
Código :
var mongoose = require('mongoose'); var passport = require('passport'); require('./models/user'); require('./passport')(passport); mongoose.connect('mongodb://localhost/passport-example', function(err, res) { if(err) throw err; console.log('Conectado con éxito a la BD'); }); … app.use(express.cookieParser()); app.use(express.urlencoded()); app.use(express.json()); app.use(express.methodOverride()); app.use(express.session({ secret: 'secretkey' })); // Configuración de Express app.use(passport.initialize()); app.use(passport.session()); ... // Rutas de Passport app.get('/logout', function(req, res) { req.logout(); res.redirect('/'); }); app.get('/auth/twitter', passport.authenticate('twitter')); app.get('/auth/facebook', passport.authenticate('facebook')); app.get('/auth/twitter/callback', passport.authenticate('twitter', { successRedirect: '/', failureRedirect: '/login' })); app.get('/auth/facebook/callback', passport.authenticate('facebook', { successRedirect: '/', failureRedirect: '/login' })); ...
Puedes ver el resto del archivo y los demás de la aplicación en el siguiente repositorio de GitHub: https://github.com/carlosazaustre/passportjs-example
El siguiente controlador, nos renderiza la página `index.html` en la que veremos el enlace al login/registro tanto con facebook como con twitter y en cuando estemos logueados, mostraremos información del usuario:
Código :
exports.index = function(req, res){ res.render('index', { title: 'Passport-Example', user: req.user }); };
Esta sería la plantilla HTML, en la que usamos el engine Jade:
Código :
extends layout block content h1= title p Welcome to #{title} if(user) ul li img(src="#{user.photo}") li Bienvenido #{user.name} li a(href='logout') Salir else ul li a(href='auth/twitter') Login con Twitter li a(href='auth/facebook') Login con Facebook
El flujo de la aplicación sería el siguiente. Primero nos muestra los enlaces para autenticarnos con nuestra cuenta en Twitter o Facebook.

Elegimos Twitter y la apliación nos redirige a la página de Twitter del API para autenticarnos.

Y por último, cuando se finaliza la autenticación, el callback nos devuelve a la URL de inicio donde vemos nuestro nombre, el enlace al `logout` y nuestra foto de twitter.

Tenéis todo el código utilizado disponible y comentado en español en este respositorio de GitHub. Espero que os sirva en vuestros proyectos y desarrollos

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por sergio el 23 de Agosto de 2014
Cómo sería en la versión 4 de express?
El tutorial esta perfecto. Saludos!
Por Miguel el 23 de Agosto de 2014
Lo que estaba necesitando, gracias !!
Por peyoromn el 24 de Agosto de 2014
500 FacebookGraphAPIError: (#100) Tried accessing nonexisting field (provider) on node type (User)
Por carlosazaustre el 24 de Agosto de 2014
La versión 4 de Express cambia algunas cosas, como las rutas. tengo un post en mi blog que comenta los cambios.
@peyoromn prueba a eliminar el campo "provider" en model/user.js, quizá la nueva versión de Passport o el API de Facebook no hagan uso de ello.
Saludos!
Por Alfredo el 08 de Septiembre de 2014
> node-gyp rebuild
C:\nodejs\login-social\node_modules\facebook\node_modules\base64>node "C:\Progra
m Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\bi
n\node-gyp.js" rebuild
gyp ERR! configure error
gyp ERR! stack Error: Can't find Python executable "python", you can set the PYT
HON env variable.
gyp ERR! stack at failNoPython (C:\Program Files\nodejs\node_modules\npm\nod
e_modules\node-gyp\lib\configure.js:103:14)
gyp ERR! stack at C:\Program Files\nodejs\node_modules\npm\node_modules\node
-gyp\lib\configure.js:64:11
gyp ERR! stack at Object.oncomplete (fs.js:107:15)
gyp ERR! System Windows_NT 6.2.9200
gyp ERR! command "node" "C:\\Program Files\\nodejs\\node_modules\\npm\\node_modu
les\\node-gyp\\bin\\node-gyp.js" "rebuild"
gyp ERR! cwd C:\nodejs\login-social\node_modules\facebook\node_modules\base64
gyp ERR! node -v v0.10.28
gyp ERR! node-gyp -v v0.13.0
gyp ERR! not ok
npm ERR! [email protected] install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script.
npm ERR! This is most likely a problem with the base64 package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-gyp rebuild
npm ERR! You can get their info via:
npm ERR! npm owner ls base64
npm ERR! There is likely additional logging output above.
npm ERR! System Windows_NT 6.2.9200
npm ERR! command "C:\\Program Files\\nodejs\\\\node.exe" "C:\\Program Files\\nod
ejs\\node_modules\\npm\\bin\\npm-cli.js" "install" "--save" "passport" "facebook
"
npm ERR! cwd C:\nodejs\login-social
npm ERR! node -v v0.10.28
npm ERR! npm -v 1.4.9
npm ERR! code ELIFECYCLE
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! C:\nodejs\login-social\npm-debug.log
npm ERR! not ok code 0
Por txesterfield el 26 de Septiembre de 2014
Solo me queda una duda, una vez que resgitras via twitter/facebook en tu aplicación al usuario... para volver a entrar en la app no debería de volver a autorizar a la app de nuevo, no? Directamente se podría loguear.
Estoy viendo que el callback de twitter devuelve un oauth_token y un oauth_verifier pero que se utilizan en la sesión. No hay manera de recuperar un token del usuario para entrar directamente sin tener que hacerle autenticarse de nuevo?
Gracias y buen trabajo.
Por danieling el 05 de Noviembre de 2014
500 FacebookGraphAPIError: (#100) Tried accessing nonexisting field (provider) on node type (User)
Comenten o borren las lineas donde aparece provider en user.js y passport.js
Por juang el 01 de Diciembre de 2014
Por juang el 01 de Diciembre de 2014
Muchas gracias!! excelente tutorial
Por Gustavo el 05 de Diciembre de 2014
set keyfacebook=896789798hhjkhjkhjkhjkh
y luego referenciarlas desde el código fuente
en fin, muy buen ejemplo
Por adelosri el 03 de Enero de 2015
Por NodeNoob el 26 de Enero de 2015
profileFields : ['id', 'displayName','photos']
del archivo user y el de crear nuevo usuario y resetean el node