# Gestionar sesiones privadas usando OpenID Connect (OIDC)

Interactúa con una API privada usando la sesión privada de Modyo con una integración OIDC. Esta integración consiste de dos pasos: hacer el sitio privado y habilitar la integración a nivel de cuenta.

# 1. Hacer el sitio privado

Un sitio privado permite que solamente los usuarios registrados en Modyo Platform puedan accesar este sitio. Para hacer el sitio privado, sigue estos pasos:

  1. En Modyo Platform, desde el menú lateral, haz click en Channels y selecciona Sitios.
  2. Haz click en tu sitio.
  3. En la sección Configuración del sitio, haz click en General.
  4. En la pestaña Privacidad, selecciona la opción Privado.

Además activa Mostrar home a visitas públicas para poder redireccionar usuarios sin sesión.

# Habilitar la integración a nivel de Reino (para todos los usuarios y sitios que pertenecen al reino)

  1. En el menú lateral, selecciona Customers y haz click en Reinos.
  2. Expande Configuración de reino y haz click en Proveedores de Identidad.
  3. Haz click en + Añadir
  4. Selecciona la integración OpenID Connect y lleno los siguientes datos:
  • Nombre del servicio
  • Client ID
  • Secret
  • Issuer
  1. Haz click en Lanzar servicio de descubrimiento para asegurar que se logró una conexión.
  2. Habilita las siguientes opciones si son necesarias:
    • Habilitar refresh token
    • Habilitar cierre de sesión remoto
    • Habilitar revocación de token
    • Habilitar sincronización de claims
  3. Asocia los campos del proveedor con los campos personalizados que tengas en Modyo OpenID Connect 1.0 specification for Standard Claims (opens new window)

# 2. Usar Axios para hacer la integración

Usaremos la librería axios para realizar una integración desde Modyo. Un patrón que resulta conveniente es crear 3 snippets distintos que se harán cargo de los aspectos básicos de una integración.

Las tareas que debes cubrir con los snippets son:

  • Un interceptor de requests para incluyan un token.
  • Un controlador de sesiones.
  • Una ventana modal que informe al usuario que su sesión va a expirar.

Primero debemos agregar la librería Axios a través de un CDN al sitio:

  1. En el menú lateral, selecciona Channels y haz click en Sitios.
  2. Haz click en tu sitio y luego haz click en Plantillas.
  3. En el apartado de Snippets, abre el archivo head y copia el siguiente código:

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

  1. Guarda los cambios.

Para crear los snippets, sigue estos pasos:

  1. En el menú lateral, selecciona Channels y haz click en Sitios.
  2. Haz click en tu sitio y luego haz click en Plantillas.
  3. En el menú lateral derecho, en la pestaña Snippets, agrega un nuevo snippet personalizado.
  4. Nombra la ruta interceptor_js y copia el siguiente código:

# Interceptar los request para que incluyan un token

// variable global que representará una instancia de axios que se encargará de hacer las peticiones de los servicios
var axios_api = axios.create();
axios_api.defaults.baseURL = 'URL DE API';

// variable global que representará una instancia de axios que se encargará de hacer las peticiones de la api de modyo
var axios_modyo=axios.create({
  baseURL: window.baseUrl + '/api/admin',
});
// variable global que representará una instancia de axios que se encargará de hacer las peticiones los json de contenido del sitio
var axios_modyo_json=axios.create({
  baseURL: {{site.url}},
});
// variable global que representará una instancia de axios que se encargará de hacer las peticiones relacionadas con la autenticación
var axios_auth = axios.create();
axios_auth.defaults.baseURL = window.baseUrl + '/auth/openidc';
// función que genera actividad en el sitio con cada petición de autenticación
var resetIdleTime = function(request){
  sessionManager.resetIdleTime();
  return request;
};
// función que agrega el token a cada uno de los request
var appendTokenToRequest = function (request) {
  return axios_auth.get('/access_token').then(function(response){
    request.headers.authorization='Bearer '+ response.data.access_token;
    return request;
  });
};
// función que maneja los errores de cada una de las peticiones y los envía a una instancia superior
var errorRequest=function(error){
  throw error;
};
axios_auth.interceptors.request.use(resetIdleTime);
axios_api.interceptors.request.use(appendTokenToRequest ,errorRequest);
  1. Cambia el nombre URL DE API por la URL donde se localice la API de Modyo Platform.

# Un controlador de sesiones

  1. Agrega otro snippet personalizado llamado controller_js y copia el siguiente código:
// se encarga de levantar el modal de advertencia que avisará el cierre próximo de la sesión, esta variable devolverá una promesa que será efectiva si se hace click en el botón Mantener Sesión y que lanzará una promesa reject en el caso de seleccionar el botón con la negativa de continuar
var modalConfirm = function() {
  return new Promise(function(resolve, reject) {
    $("#session-modal").modal({
      backdrop: "static",
      keyboard: false,
      show: true
    });
    $("#session-modal-yes").on("click", function() {
      resolve("keep session");
      $("#session-modal").modal("hide");
    });
    $("#session-modal-no").on("click", function() {
      reject("destroy session");
      $("#session-modal").modal("hide");
    });
  });
};
// será la que se encarga de al iniciarse comenzar el tracking del tiempo para levantar este modal y manejar del lado Front la sesión a continuación se explica cada una de las propiedades y métodos de este objeto que maneja la sesión
var sessionManager = {
  // propiedad que define el tiempo desde la última actividad hasta el fin de la sesión en segundos (ojo no el tiempo de refresco del token sino el de finalización de la sesión, es recomendado que este sea un minuto menor al declarado por el provider del Open ID Connect para tener un poco de holgura con la sesión y el cierre de la misma sea 100% valido)
  timeToEndSessionInSeconds: 900,
  // propiedad donde se define el tiempo de levantamiento del modal de inactividad desde la última acción o petición en la página
  timeToRaiseWarningModalInSeconds: 720,
  // propiedad que guarda el timestamp del último momento de actividad del sessionManager
  lastActionTimeInThisWindow: new Date().getTime(),
  // función que convierte segundos a milisegundos
  secondsToMilisecs: function(minutes) {
    return minutes * 1000;
  },
  // propiedad para almacenar el interval id de revisión de eventos de sesión
  intevalId:null,
  // función que determina si se esta accediendo a la aplicación desde el modyoShell o no
  isModyoAppShell: function() {
    return /; Modyo_App_Shell/.test(navigator.userAgent);
  },
  // método que debe ser ejecutado en cada carga de página para comenzar el proceso de eventos de sesión a hacer seguimiento recomendado hacer esta invocación sessionManager.init() en el head del layout para comenzar a trackear la sesión (en algunos casos se define que los developers no lancen esta invocación en ese caso la API de prueba a conectar debe tener también este if y así lograrás que axios_api sirva para el entorno develop y el de desarrollo uno con sesión y el otro sin sesión manager)
  init: function() {
    this.resetIdleTime();
    this.intevalId=this.interval();
  },
  // reinicia el tiempo de espera o crea una nueva actividad en el sitio
  resetIdleTime: function() {
    this.lastActionTimeInThisWindow = new Date().getTime();
    var sessionEndTime =
      this.lastActionTimeInThisWindow +
      this.secondsToMilisecs(this.timeToEndSessionInSeconds);
    localStorage.setItem("timeToEndSession", sessionEndTime);
    var raiseWarningModalTime =
      this.lastActionTimeInThisWindow +
      this.secondsToMilisecs(this.timeToRaiseWarningModalInSeconds);
    localStorage.setItem("timeToRaiseWarningModal", raiseWarningModalTime);
  },
  // método que inicia la actividad cada segundo js que maneja los eventos de sesión
  interval: function() {
    var self = this;
    return setInterval(this.checkSessionEvents, 1000, self);
  },
  // método que levanta el modal de warning time
  raiseModal: function() {
    return modalConfirm();
  },
  // método que cierra sesión y limpia storage
  logout: function() {
    localStorage.clear();
    sessionStorage.clear();
    clearInterval(this.intevalId);
    var withRedirect =
      arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
    if (withRedirect) {
      window.location.href =
        "{{site.account_url}}/logout?multi=true&redirect_to=https://modyo.com";
    } else {
      window.location.href = "{{site.account_url}}/logout?site={{site.uuid}}";
    }
  },
  // método que revisa los eventos de sesión para determinar si es momento de cierre de la misma o de mantenerla después de mostrar el modal
  checkSessionEvents: function(self) {
    var sessionEndTime = localStorage.getItem("timeToEndSession");
    var raiseWarningModalTime = localStorage.getItem("timeToRaiseWarningModal");
    var diffInSecsToShow =
      Math.round((sessionEndTime - new Date().getTime()) / 1000) > 0
        ? Math.round((sessionEndTime - new Date().getTime()) / 1000)
        : 0;
    var expirationTimeHtml = document.querySelector("#expiration-time");
    var timeNow = new Date().getTime();
    expirationTimeHtml.innerText = diffInSecsToShow;
    if (sessionEndTime - timeNow < 0) {
      self.logout();
    } else if (raiseWarningModalTime - timeNow < 0) {
      self
        .raiseModal()
        .then(function(response) {
          axios_auth.get("/access_token");
        })
        .catch(function(err) {
          self.logout();
        });
    } else {
      if (($("#session-modal").data("bs.modal") || {})._isShown) {
        $("#session-modal").modal("hide");
      }
    }
  }
};
  1. Cambia el código redirect_to=https://modyo.com"; a una URL donde quieras redirigir a tus usuarios.

# Una ventana modal que informe al usuario que su sesión va a expirar

Este es el modal a activar en el paso anterior con bootstrap para el manejo del warning modal.

  1. Agrega otro snippet personalizado llamado sessionmodal y copia el siguiente código:
<div
  id="session-modal"
  class="modal fade"
  tabindex="-1"
  role="dialog"
  aria-labelledby="session-modal-label"
>
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="session-modal-label">
          Su sesión va a expirar
        </h5>
      </div>
      <div class="modal-body text-center">
        <p>
          Su sesión va a expirar en <span id="expiration-time"></span> segundos.
        </p>
        <p>¿Quiere mantener su sesión?</p>
      </div>
      <div class="modal-footer">
        <button id="session-modal-yes" type="button" class="btn btn-primary">
          Si
        </button>
        <button
          id="session-modal-no"
          type="button"
          class="btn btn-secondary"
          data-dismiss="modal"
        >
          No
        </button>
      </div>
    </div>
  </div>
</div>

# Conclusión

Con estos snippets, ya puedes lograr interactuar con la API usando una sesión privada a través de OIDC gestionada por Axios. El siguiente paso será agregar estos snippets a tu sitio usando los siguientes códigos:

  • Interceptor: {% snippet "interceptor_js" %}
  • Controller: {% snippet "controller_js" %}
  • SessionModal: {% snippet "sessionmodal" %}
Last Updated: 4/5/2022,