Saltar al contenido principal
Auth0 admite la especificación OpenID Connect Back-Channel Logout 1.0 en todos los inquilinos con una suscripción al plan Enterprise. Esta especificación aprovecha el identificador de sesión (sid) incluido en los y los tokens de cierre de sesión para coordinar la finalización de la sesión mediante comunicación por canal secundario. Los distintos identificadores de sesión representan sesiones individuales de un agente de usuario o dispositivo dentro de tu inquilino. Los tokens de cierre de sesión identifican al usuario final y la sesión que se debe cerrar.

Comunicaciones de canal secundario

Para usar Back-Channel Logout, una aplicación debe exponer un URI de Back-Channel Logout, accesible desde el servidor del inquilino, donde la aplicación espera recibir las solicitudes con el Logout Token. Cuando una aplicación recibe esta solicitud, debe borrar el estado de la sesión local que coincida con los claims del token.
Para que Back-Channel Logout funcione, las aplicaciones deben poder recibir comunicaciones de canal secundario.

Tokens en las comunicaciones de Back-Channel Logout en OIDC

Las aplicaciones no pueden depender de las para determinar qué sesión finalizar cuando las comunicaciones se realizan a través del canal secundario. En su lugar, el servicio se basa en un identificador de sesión compartido (sid) en los ID Token y los Logout Token. Cuando los usuarios finales se autentican correctamente con Auth0 durante el inicio de sesión, el emite tokens de acceso e ID. Los Logout Token se generan cuando se destruye una sesión, por ejemplo, mediante una acción de cierre de sesión o la revocación de una sesión. Tanto los ID Token como los Logout Token contienen las claims que su aplicación necesita para facilitar el flujo de trabajo de cierre de sesión por canal secundario. Para obtener más información sobre las claims, lea Claims de JSON Web Token.
Flujo de trabajo del cierre de sesión por canal secundario
  1. Inicio de sesión: durante la autenticación del usuario, el inquilino de Auth0 agrega el sid al ID Token.
  2. Inicio de sesión: la aplicación almacena el identificador de sesión recibido en su propio almacén de sesiones y lo asocia con la sesión específica de la aplicación.
  3. Cierre de sesión: el IdP llama a la URL de devolución de llamada de cierre de sesión previamente registrada y envía el Logout Token a este endpoint. El token contiene el user_id (sub) y el sid, junto con otros parámetros.
  4. Cierre de sesión: el backend de la aplicación debe validar el Logout Token de acuerdo con la especificación de OIDC y extraer el sid. Luego, el backend puede usar ese valor para encontrar la sesión asociada con el identificador y finalizarla según sea necesario.
La respuesta esperada es HTTP 200 para un cierre de sesión correcto. Si recibe HTTP 400, una solicitud incorrecta o malinterpretada, puede usar nuestros consejos para solucionar el problema. Para obtener más información, lea Configurar Back-Channel Logout.

Cómo funciona

Este caso de uso de ejemplo muestra cómo funciona Back-Channel Logout con más de una aplicación:
Caso de uso de Back-Channel Logout con varias aplicaciones
  1. Durante la configuración de la aplicación, la Aplicación A registra un URI de Back-Channel Logout en Auth0.
  2. Durante la configuración de la aplicación, la Aplicación B registra un URI de Back-Channel Logout en Auth0.
    Las URL de OIDC Back-Channel Logout deben:
  3. Durante el inicio de sesión del usuario final, un usuario se autentica con Auth0 para acceder a la Aplicación A.
  4. Auth0 envía un token de ID con sid a la Aplicación A. Para obtener más información, consulte Estructura del ID Token.
  5. El usuario se autentica con Auth0 para acceder a la Aplicación B.
  6. Auth0 envía un token de ID con el mismo sid a la Aplicación B. Su aplicación debe almacenar la información de la sesión.
  7. Durante el cierre de sesión, la Aplicación A u otras entidades inician el cierre de sesión en el front-channel.
  8. Auth0 finaliza la capa de sesión de Auth0 mediante la cookie de sesión.
  9. Auth0 llama al URI de Back-Channel Logout de la Aplicación A y envía el Logout Token.
  10. La Aplicación A valida el Logout Token y finaliza la sesión.
  11. Auth0 llama al URI de Back-Channel Logout de la Aplicación B y envía el Logout Token.
  12. La Aplicación B valida el Logout Token y finaliza la sesión.
Las solicitudes de cierre de sesión por canal secundario se colocan en una cola asíncrona y se procesan lo antes posible. En situaciones de alta carga, puede haber un ligero retraso antes de que se ejecute la solicitud de cierre de sesión, así que diseñe sus aplicaciones para manejar esta consistencia eventual.

Token de ejemplo

La aplicación debe poder analizar y validar para utilizarlos como Logout Tokens con Auth0. Para obtener más información, lea Validar tokens web JSON. Una vez que la aplicación valide y decodifique el token, su contenido será similar al del siguiente ejemplo:
JSON
{
  "iss": "https://artex-dev.eu.auth0.com/",
  "sub": "auth0|602e93db83fa6f00749a23e6",
  "aud": "TuhNLv7ulXD3RfyLlSMbOvszzwJJFPpO",
  "iat": 1698160928,
  "exp": 1698161048,
  "jti": "44a91215-dfb4-4dfe-a1eb-fcafa911deba",
  "events": {
    "http://schemas.openid.net/event/backchannel-logout": {}
  },
  "trace_id": "81b336a94a4a5707",
  "sid": "375UIp_ID5mCTClIeBEHpXfGwq51tF_L"
}

SDKs de Auth0

Ya se incluyen un ejemplo completo y código listo para producción en la sección Back-Channel Logout Example de nuestro SDK express-openid-connect.

Ejemplos de implementación

Almacenamiento de sesiones

El ejemplo de almacenamiento de sesiones está desarrollado en Node (Express) y se basa en la aplicación web de ejemplo de Express OpenID Connect. En la pestaña de sesiones de la aplicación, expón la ruta que configuraste para recibir el Logout Token. Valida el token y finaliza la sesión del usuario.
Este ejemplo usa un almacén de sesiones en memoria con fines de demostración.
routes/index.js
const express = require('express');
const router = express.Router();
const { requiresAuth } = require('express-openid-connect');

// middleware para validar el token de cierre de sesión
const requiresValidLogoutToken = require('../middlewares/validateLogoutToken');

// función auxiliar para eliminar sesiones de usuario
const deleteUserSessions = require('../utils/sessions');

// nueva ruta para recibir tokens de cierre de sesión por backchannel
// debe configurarse en la pestaña Application -> Sessions
// en el Dashboard de administración de Auth0
router.post(
  '/backchannel-logout',
  requiresValidLogoutToken,
  function (req, res, next) {
    // en este punto el token de cierre de sesión es válido, verificado por el middleware requiresValidLogoutToken
    // se puede acceder a él desde el objeto de solicitud: req.logoutToken

    // eliminar la sesión del usuario para que se cierre su sesión
    deleteUserSessions(
      req.app.locals.sessionStore,
      req.logoutToken.sub,
      req.logoutToken.sid
    );

    res.sendStatus(200);
  }
);

router.get('/', function (req, res, next) {
  res.render('index', {
    title: 'Auth0 Webapp sample Nodejs',
    isAuthenticated: req.oidc.isAuthenticated(),
    headline: process.env.APP_NAME,
    backgroundColor: process.env.BACKGROUND_COLOR,
    baseURL: process.env.BASE_URL,
  });
});

router.get('/profile', requiresAuth(), function (req, res, next) {
  res.render('profile', {
    userProfile: JSON.stringify(req.oidc.user, null, 2),
    title: 'Profile page',
    headline: process.env.APP_NAME,
    backgroundColor: process.env.BACKGROUND_COLOR,
    baseURL: process.env.BASE_URL,
  });
});

module.exports = router;
middlewares/validateLogoutToken.js
// Este middleware valida el logout token según se define aquí:
// https://openid.net/specs/openid-connect-backchannel-1_0.html#Validation

const jose = require('jose');

async function requiresValidLogoutToken(req, res, next) {

  // obtener el conjunto de claves remotas para la verificación del token
  const JWKS = jose.createRemoteJWKSet(
    new URL(process.env.ISSUER_BASE_URL + '/.well-known/jwks.json')
  );

  const logoutToken = req.body.logout_token;

  if (!logoutToken) {
    res.status(400).send('Need logout token');
  }

  try {
    const { payload, protectedHeader } = await jose.jwtVerify(
      logoutToken,
      JWKS,
      {
        issuer: process.env.ISSUER_BASE_URL + '/',
        audience: process.env.CLIENT_ID,
        typ: 'JWT',
        maxTokenAge: '2 minutes',
      }
    );

    // Verificar que el Logout token contenga un claim sub, un claim sid, o ambos
    if (!payload.sub && !payload.sid) {
      res
        .status(400)
        .send(
          'Error: Logout token must contain either sub claim or sid claim, or both'
        );
    }

    // Verificar que el logout token contenga un claim events
    // cuyo valor sea un objeto JSON que contenga el nombre de miembro http://schemas.openid.net/event/backchannel-logout
    if (!payload.events['http://schemas.openid.net/event/backchannel-logout']) {
      res
        .status(400)
        .send(
          'Error: Logout token must contain events claim with correct schema'
        );
    }

    // Verificar que el Logout token no contenga un claim nonce.
    if (payload.nonce) {
      res
        .status(400)
        .send('Error: Logout token must not contain a nonce claim');
    }

    // adjuntar el logout token válido al objeto de solicitud
    req.logoutToken = payload;

    // el token es válido, invocar el siguiente middleware
    next();
  } catch (error) {
    res.status(400).send(`Error:  ${error.message}`);
  }
}

module.exports = requiresValidLogoutToken;

Almacén de Logout Tokens

Un enfoque habitual para el almacenamiento de tokens es definir un almacén de cierre de sesión como alternativa al modelo de almacén de sesiones. La aplicación o las aplicaciones mantienen una colección de Logout Tokens en la capa de persistencia. Cada vez que la aplicación necesita comprobar su estado de autenticación, consulta el almacén de Logout Tokens para determinar si su sesión sigue activa. El almacén de cierre de sesión elimina periódicamente la información obsoleta para conservar solo la información necesaria.
Almacén de tokens de cierre de sesión

Consideraciones de seguridad

Los Logout Tokens de canal secundario se entregan a través de Internet; por lo tanto, los endpoints de devolución de llamada que los reciben deben seguir las prácticas recomendadas para garantizar un funcionamiento confiable y seguro. La siguiente lista de recomendaciones no es exhaustiva, y siempre debe tener en cuenta las situaciones específicas de implementación y operación para adaptarla según corresponda. En la lista siguiente, cualquier aplicación que maneje los Logout Tokens de canal secundario se denomina “apps”.
  • Las apps deben poder almacenar el ID de sesión (claim sid) recibido durante el inicio de sesión del usuario para recuperarlo más adelante al recibir un Logout Token por canal secundario.
  • Las apps deben verificar todos los tokens recibidos de acuerdo con las prácticas recomendadas para la validación de JWT.
  • Las apps deben aceptar únicamente tokens emitidos por inquilinos de confianza. Un actor malicioso puede intentar enviar tokens emitidos por otros inquilinos de Auth0; dichos intentos deben rechazarse.
  • Las apps deben aceptar tokens solo cuando contengan un valor sid (ID de sesión) que la app reconozca. Los tokens que contengan un ID de sesión no válido (ya sea porque ha expirado o porque no se reconoce) deben rechazarse.
  • Las apps deben exponer los endpoints de devolución de llamada únicamente mediante TLS. No se permiten canales de comunicación sin cifrar.
  • Se recomienda que las apps acepten solicitudes solo de la lista publicada de direcciones IP salientes.
  • Se recomienda que las apps sigan las prácticas recomendadas generales en materia de monitoreo, registro y limitación de tasa; sin embargo, los detalles de estas quedan fuera del alcance de este documento.
  • Se recomienda que las apps eliminen periódicamente las sesiones obsoletas o expiradas.
  • Cualquier cambio en la dirección del endpoint debe sincronizarse con la configuración del inquilino para garantizar que los Logout Tokens siempre se entreguen a la URL correcta de devolución de llamada de cierre de sesión por canal secundario.