Llevo un tiempo desarrollando en mis ratos libres un add-in para Microsoft Outlook utilizando el nuevo modelo de web add-ins que posibilita extender las capacidades de Microsoft Office utilizando un mismo código que se ejecuta independiente de la plataforma, ya sea Windows, macOS, iOS, Android o web.

Este modelo de desarrollo de extensiones para Office se basta fundamentalmente en HTML+Javascript, cuyo código alojaremos en nuestro propio servidor web y que será accedido por Office en el momento de su ejecución.

Como podréis intuir del modelo, el código de nuestra extensión se ejecuta en el lado del cliente.

Licenciando nuestro addin de Microsoft Office

Si queremos publicar nuestro add-in en la Office Store y queremos que sea de pago, Microsoft pone a disposición del desarrollador un servicio web SOAP y REST que nos permite comprobar el estado de licenciamiento de un usuario; esto es, si ha pagado licencia o bien tiene una trial, si la trial expiró, si está en un modelo de suscripción, etc...

El funcionamiento es simple: al ejecutarse nuestro add-in, este lleva un token que tendremos que enviar al servicio web para que nos devuelva esta información. Como estamos desarrollando en Javascript es mucho más sencillo llamara la variante REST que se encuentra aquí:

https://verificationservice.officeapps.live.com/ova/verificationagent.svc/rest/verify

Como podéis ver, no devuelve JSON, sino XML.

Ya que por defecto los Office add-ins llevan jQuery, podemos utilizar esta librería para llamar fácilmente al servicio. Nos quedaría parecido a esto:

$.ajax({
   type: "GET",
   url: 'https://verificationservice.officeapps.live.com/ova/verificationagent.svc/rest/verify?token=' + licenseToken,
   dataType: "xml",
   async: false,
   success: function (xml) {
      $(xml).find('VerifyEntitlementTokenResponse').children().each(function () {
         entitlementTokenResponse[this.tagName] = this.textContent;
      });
   },
   error: function (xml) {
      throw new Error("OVA error: " + xml.statusText);
   }
});

Sin embargo, si examinamos la documentación de uso del servicio de licenciamiento nos advierte de lo siguiente: Calling the Office Store verification service from client-side code is not supported. You must use server-side code to query the Office Store verification web service. Una prueba de ejecución nos confirmará que Microsoft no va de farol aquí.

Vaya, ¿nada de client-side code? ¡Pero si nuestro add-in tiene que escribirse en Javascript! ¿Estamos condenados a que si usamos este nuevo framework nuestros add-in sean gratuitos por no poder llamar al servicio? Afortunadamente no...

Problema... ¿insalvable? CORS

Hay un motivo por el cual Microsoft establece esto en su documentación: el servicio web de verificación de licencias no implementa CORS.

CORS, Cross-Origin Resource Sharing es un mecanismo que permite al código ejecutado desde un dominio determinado (ej: calnus.com) solicitar recursos de un dominio externo (ej: cdn.microsoft.com). Sin el cumplimiento de esta política, ningún navegador actual permitirá llamadas a recursos externos a nuestro dominio.

¿Cómo se implementa CORS? Es sencillo: cuando solicitamos un recurso externo, en la cabecera HTTP de la respuesta se especifica qué dominios están permitidos. Este podría ser un ejemplo:

Access-Control-Allow-Origin: http://www.example.com

Si llamamos a un servicio web que no implementa CORS, y por tanto no devuelve esto en su cabecera; obtendremos un acceso denegado por parte de nuestro motor Javascript. CORS puede parecer problemático, pero en realidad es una excelente medida de seguridad.

El servicio de verificación de licencias de la Office Store NO soporta CORS y este es el motivo por el que Microsoft no da soporte a que sea llamado desde el lado del cliente. ¡Pero podemos solucionarlo!

Azure Functions Proxies al rescate

Hay una manera rápida, sencilla y limpia de solucionar este problema: Azure Functions Proxies. Se trata de una nueva característica de Azure Functions que nos permite hacer lo que el nombre sugiere: un proxy de APIs. Esto es especialmente útil cuando debemos hacer llamadas a multitud de API distintas y queremos unificarlas bajo una misma URL.

Así podemos convertir https://verificationservice.officeapps.live.com/ova/verificationagent.svc/rest/verify en https://calnusapiproxy.azurewebsites.net/ova y agregar en este último un CORS que nos permita la llamada del servicio. Lo que ocurriría a continuación es lo siguiente:

  1. Nuestro código Javascript llama a https://calnusapiproxy.azurewebsites.net/ova, que es Azure Functions Proxy.
  2. Azure Functions convierte la llamada al backend https://verificationservice.officeapps.live.com/ova/verificationagent.svc/rest/verify y obtiene una respuesta.
  3. A la respuesta le agrega cabeceras HTTP CORS si es que así lo hemos especificado, en nuestro caso https://calnusapiproxy.azurewebsites.net/.
  4. Nuestro código recibe la respuesta con el CORS correcto.

Os dejo con un par de capturas de pantalla de la configuración.

¡Happy CORS!