Node Para Intermedios: Creando un login con Facebook usando PassportJS en 5 pasos

En esta ocasión, retomando los artículos sobre JavaScript les traigo una aplicación muy básica que lo que hace es saludarnos personalmente, enseñar nuestra foto de perfil y decir desde donde venimos, es decir, el proveedor que hemos usado para iniciar sesión. Como parte de este post aprenderemos desde cero a crear esta aplicación, desde montar el servidor de Express, hasta pasarle los datos del usuario al template.

Finalmente, antes de empezar quiero comentar que por esta vez solo vamos a ver la posibilidad de autenticarnos con Facebook aunque si les interesa hacerlo con alguno en especial solo tienen que dejarlo en un comentario o comentármelo por alguna de mis redes y estaré encantado de hacer un bonus de este post.

He preparado una serie de pasos con el fin de que crear esta aplicación sea un proceso más fácil para ti. Al final he dejado algunos recursos para mejorarla o sobre los que documentarte y el repositorio que representa como he ido haciendo esta aplicación paso a paso.

1. Instalamos todas las dependencias que vamos a usar a lo largo del proyecto y las importamos en nuestro archivo de el servidor

Como en veces anteriores, usaremos NPM para instalar todas las dependencias que necesitamos. Puedes copiar el comando :)

$ npm install --save express pug passport passport-facebook mongoose express-session body-parser cookie-parser

Debes de tener en cuenta, que si vas a usar ES6, como yo haré en este tutorial debes de instalar algunos paquetes más:

$ npm install --save babel-register babel-preset-es2015

Tras esto, en el archivo de nuestro servidor(server.js) importamos todos los módulos recientemente instalados ya que va a ser uno de los pocos archivos que tengamos por lo que tenemos que llamar a la totalidad de ellos:

/*
  Module dependencies
*/
import express from 'express'  
import mongoose from 'mongoose'  
import passport from 'passport'  
import facebook from 'passport-facebook'  
import User from './models/user'  
import pug from 'pug'  
import config from './config' // Para no definir claves directamente en el código, es opcional.  
import bodyParser from 'body-parser'  
import cookieParser from 'cookie-parser'  
import session from 'express-session'  

2. Creamos el servidor de Express y nos conectamos a MongoDB con Mongoose

Para crear una base simple me limitaré a conectarme con la base de datos, la cual es MongoDB y haré que la rute raíz envíe un Hello World que posteriormente modificaré así como la función para inicializar el servidor. Lo más importante para el final:

// Definición de variables
 +const app = express()
 +const port = config.env.port || 3000
 +
 +// Conexión con la base de datos
 +mongoose.connect(config.db.url, (err, res) => {
 +  if (err) throw err
 +  console.log('[DATABASE] Database running correctly. Now you can start sending/receiving data.')
 +})
 +
 +/*
 +  Rutas de Express
 +*/
 +app.get('/', (req, res) => {
 +  res.send('Hello World')
 +})
 +
 +// Iniciar el servidor
 +app.listen(port, () => {
 +  console.log(`[APP] Running on port ${port}.`)
 +})

3. Creamos la configuración de PassportJS para que se conecte con el OAuth de Facebook

Lo más importante, debemos de crear la estrategia de Facebook, que contendrá las claves de acceso para poder realizar login en nuestra aplicación. También debemos de añadir dos middlewares para garantizar la serialización y deserialización del objeto usuario. Añadiremos finalmente la ruta que nos llevará a Facebook para autenticarnos y su callback.

Este punto se divide en dos subpuntos, el primero centrado en crear una aplicación desde Facebook Developers y el segundo centrado en lo anteriormente mencionado:

3.1. Registrar una aplicación en el sitio Facebook Developers

Accedemos a la página principal del sitio para desarrolladores de Facebook y con nuestra sesión iniciada damos click en Mis Aplicaciones y obviamente después de esto en Añadir una nueva aplicación:

Nos pedirá diversos detalles tales como la plataforma(Sitio Web), nombre, URL... Puedes hacerlo usando un step-by-step guide como muestro en esta imagen o directamente puedes saltarte los pasos y crear tu App Id, el cual necesitaremos para configurar PassportJS. El botón se encuentra en la esquina superior derecha.

Lo hicimos! Hemos creado nuestra aplicación. Ahora hay que anotar el identificador de la aplicación y la clave secreta de la aplicación, con el fin de pasarselas a PassportJS más adelante.

Recuerda! Especifica la URL de la aplicación correcta, en caso de estar en modo de testing puedes usar algo como lo que yo puse en la imagen. Lo recomendable aun así es establecer misitio.test para irnos preparando para producción.

3.2. Escribir la conexión con PassportJS, sus respectivos middlewares y sus rutas.

Es la parte más importante de nuestra aplicación. Sin esta parte de código no podremos conectarnos con Facebook para hacer el login.

const facebookStrategy = facebook.Strategy

// Express configuration for PassortJS
app.use(cookieParser())  
app.use(bodyParser())  
app.use(session({ secret: config.session.secret }))

// Database connection
mongoose.connect(config.db.url, (err, res) => {  
  if (err) throw err
  console.log('[DATABASE] Database running correctly. Now you can start sending/receiving data.')
})

// Passport middlewares
passport.serializeUser((user, done) => {  
  done(null, user.id)
})

passport.deserializeUser((id, done) => {  
  User.findById(id, (err, user) => {
    done(err, user)
  })
})

app.use(passport.initialize())  
app.use(passport.session())

// Passport Strategies
passport.use(new facebookStrategy({  
  clientID: config.fb.clientID,
  clientSecret: config.fb.clientSecret,
  callbackURL: config.fb.callback,
  profileFields: ['id', 'emails', 'displayName', 'picture']
  }, (accessToken, refreshToken, profile, done) => {
        process.nextTick(() => {
          User.findOne({provider_id: profile.id}, (err, user) => {
            if (err) return done(err)
            if (user) return done(null, user)
            else {
              var newUser = new User()
              newUser.provider_id = profile.id
              newUser.name = profile.displayName
              newUser.photo = profile.photos[0].value
              newUser.provider = 'facebook'

              newUser.save((err) => {
                if(err) throw err
                return done(null, newUser)
              })
            }
          })
        })
      }
  ))

/*
  Passport routes
*/
app.get('/login/facebook', passport.authenticate('facebook'))  
app.get('/login/facebook/callback', passport.authenticate('facebook', { successRedirect: '/user', failureRedirect: '/' }))  

4. Creamos un modelo y lo registramos en Mongoose

Como habrás visto antes, Passport se encarga de guardar el usuario en una base de datos, para esto usa un modelo al que hemos llamado User y que vamos a proceder a definir ahora:

import mongoose from 'mongoose'

const schema = new mongoose.Schema({  
  provider_id: {type: String, unique: true},
  name: String,
  photo: String,
  provider: String
})

module.exports = mongoose.model('User', schema)  

5. Creamos la template donde ocurrirá la magia y una ruta para que la sirva

Finalmente, necesitamos definir la ruta en la que vamos a enseñar todos los datos. Lo haremos tal y como habíamos definido la ruta /en el paso 2:

app.get('/user', (req, res) => {  
  res.render('user', {user: req.user})
})

Tenemos también que definir la vista a la que estamos llamando desde la carpeta views:

html  
  head
    meta(charset='UTF-8')
    title #{user.name} | Aplicación de ejemplo con autenticación
  body
    div.app
      section.app-container
        article.user
          figure
            img(src=user.photo)
          h1 Bienvenido, #{user.name}
          h2 Gracias por inciar sesión usando #{user.provider}

Si todo sale bien, al ir a http://localhost:3000 y logearnos con Facebook veremos esto:

Felicidades! Hemos creado nuestra primera aplicación con autenticación social. Recuerda que si tienes dudas, sugerencias o problemas al seguir este tutorial puedes dejar un comentario abajo.

Enlaces Relacionados

Repositorio en Github

Commits by Miguh Ruiz at social-login | Github

PassportJS Docs

Facebook Login - Facebook Developers

FB.login() - Facebook SDK

Serie Anterior: Node Para Principiantes - Miguh Ruiz Blog