Rubén Bernárdez

Desarrollador en Biko

Autenticación básica HTTP con NodeJS usando Passport

Durante el desarrollo de un nuevo proyecto estarás interesado en que alguien vaya probando tu aplicación, conozca el avance y te de feedback. Pero aún no lo has terminado, por lo que no quieres que nadie más pueda verlo.

Una solución para evitar que cualquiera pueda acceder es añadirle una autenticación básica HTTP. Cuando alguien intente acceder, el navegador le pedirá que introduzca un usuario y contraseña. Es el método de autenticación más básico que podemos añadir a una aplicación web.

Es tan básico que las credenciales introducidas por el usuario se enviarán al servidor únicamente codificadas en Base64, por lo que no es recomendable para aplicaciones en producción ya que las credenciales no se envían ni cifradas ni seguras.

La autenticación básica HTTP tampoco implementa un método estándar para "desloguear" al usuario, por lo que no es una buena solución si buscas sesiones de usuario.

Cómo funciona la autenticación básica HTTP

Si el usuario aún no está autenticado, la respuesta a una petición de una página protegida, el servidor debe responder con un código HTTP 401 y con una cabecera WWW-Authenticate:

WWW-Authenticate: Basic realm="Zona restringida, debe autenticarse"

En este ejemplo el Mensaje "Zona restringida, debe autenticarse" le aparecerá al usuario cuando el navegador le pida el usuario y contraseña.

Cuando el usuario introduzca sus datos de acceso, el navegador web enviará una nueva petición a la página con una cabecera Authorization donde irán codificados en Base64 en usuario y contraseña en una cadena con el formato usuario:contraseña

Authorization: Basic c3VwZXJ1c3VhcmlvOjEyMzQ1

Prueba a descodificar la cadena c3VwZXJ1c3VhcmlvOjEyMzQ1 y verás los datos de acceso que en este ejemplo introdujo el usuario.

Implementación usando passport

Passport es el más famoso middleware de NodeJS para implementar sistemas de autenticación en tus aplicaciones.

Pongamos en marcha la autenticación básica HTTP. Empecemos configurado passport para que nos verifique que el usuario y contraseña son correctos. Para simplificar el ejemplo, el usuario y contraseña los tenemos directamente en el código, aunque para no tener la contraseña visible y subida a nuestro repositorio del proyecto la codificaremos usando la herramienta de consola htpasswd:

$ htpasswd -n foo

La herramienta te pedirá que introduzcas la contraseña y al finalizar te aparecerá una cadena de texto con <usuario>:<contraseña cifrada>.

passport.use(new BasicStrategy(
  {
    realm: 'Private project, you must authenticate'
  },
  function(username, password, done) {
    // The password is: bar
    if (username === 'foo' && htpasswd.verify('$apr1$QNz1wNjZ$YFyKIPRxB0tcpOYmXvitK1', password)) {
      const user = { name: username };
      return done(null, user);
    }
    return done(null, false);
  }));

Cuando las credenciales las hayamos validado devolveremos un objeto con los datos que queremos que la aplicación tenga disponibles, en nuestro ejemplo sólamente el nombre del usuario. done(null, user).

Si las credenciales no son válidas, devolveremos un false en su lugar: done(null, false);

El siguiente paso es decirle a nuestro servidor web que use passport con la autenticación básica HTTP:

app.use(passport.authenticate('basic', { session: false }));

Usando app.use cualquier llamada a nuestro servidor estará protegida. Si sólo deseamos proteger una página, en vez de usar app.use, podemos utilizar password.authenticate en nuestro routing:

app.get('/', passport.authenticate('basic', { session: false }), (request, response) => {
  response.send(`Bienvenido a mi proyecto privado, ${request.user.name} :)`);
});

Puedes encontrar más detalles del sistema de autenticación básica HTTP en RFC 2617: HTTP Authentication: Basic and Digest Access Authentication