Skip to content

Servicio autenticación - Integración

Introducción

En este documento se explica cómo integrar la autenticación y SSO (Single Sign On) de Nautilus. Lee autenticación para entender el sistema de autenticación desde un punto de vista funcional. No se debe confundir el concepto de autenticación en el que se garantiza la identidad de un usuario con el concepto de autorización donde se comprueba si un usuario puede realizar o no una acción sobre un sistema.

Nautilus como proveedor de autenticación usa dos formas de autenticación de usuarios:

  • Mediante Open Id Connect (OIDC): Para cuentas externas con unas cuentas conocidas que tenemos validadas como clientes.

  • Nautilus provider (OAuth 2.0): Usuarios propios de nautilus donde tenemos tanto el usuario como la contraseña de la cuenta.

Autenticación (OAuth 2.0)

El inicio de autenticación suele comenzar cuando un cliente (aplicación web) intenta hacer una petición no autenticada al API. El navegador del cliente es redirecciónado desde el cliente a la página de login de Nautilus. Cuando el usuario está autenticado es redirigido a la web del cliente con un token firmado que permite la comunicación con el API, provee tambien un token de refresco para mantener el token de acceso válido durante la sesión, el token caduca cada 5 minutos.

Diagrama autenticación básico

La aproximación de Nautilus provider (OAuth 2.0) se puede observar en el siguiente diagrama, la web APP intenta acceder a un recurso del API, el API al validar el token observa que ha caducado, o es inválido. Rechaza la petición y la APP debe refrescar el token con el sistema de autenticación, en nuestro caso https://login.nautilus.app, una vez obtenido el token verificado tiene que repetir la petición con el nuevo token.

Flujo de autenticación por cookies (Deprecado)

Diagrama autenticación

  1. Se solicita un recurso al API (con un token inválido).
  2. La APP válida la cookie para ver si puede refrescar el token.
  3. Si la cookie es inválida se redirige a la pantalla de login para hacer un nuevo inicio de sesión.
  4. El usuario se loguea mediante el formulario.
  5. El proveedor de autenticación guarda una nueva cookie válida y nos responde con un token válido.
  6. Se usa ese token para obtener el access-token (5 caducidad).
  7. Se accede correctamente al recurso del API usando el access-token.

Segundos más tarde ...

  1. La APP detecta que el access-token está caducado y devuelve error 401 unauthorized - token expired.
  2. El navegador solicita un nuevo access-token al proveedor de autenticación.
  3. La APP valida la cookie de dominio (id_token) y devuelve un nuevo access-token.
  4. El acceso al API vuelve a ser correcto.

_Días más tarde o si el usuario se desloguea del proveedor de autenticación

  1. El navegador solicita un nuevo access-token a la APP.
  2. La APP valida la cookie de dominio y devuelve error 401 unauthorized - token expired.
  3. Se redirige a la página de login y vuelta a empezar ...

El problema por el que se ha deprecado este proceso es la imposibilidad de usar las aplicaciones en navegacion privada, porque los navegadores prohiben compartir cookies entre dominios, y se prevee que se prohiba tambien sin navegación privada. No es una buena practica esta necesidad.

Nuevo flujo de autenticación: Authorization Code Flow con PKCE (v2)

Nautilus ahora ofrece un nuevo flujo de autenticación en el que no se utilizan cookies. Este flujo es el Authorization Code Flow con PKCE, donde la aplicación cliente tendrá que intercambiar un código de autorización para obtener el access-token.

poner primer flow Diagrama autenticación Authorization Code Flow con PKCE

  1. Se solicita un recurso de al API (con un token inválido).
  2. La APP genera un code-verifier y un code-challenge. El code-verifier lo deberá guardar en el storage del navegador y el code-challenge se deberá enviar en la petición.
  3. Envía el código al proveedor de autenticación, si el proveedor tiene una sesión válida nos envia un token.
  4. Redirecciona hacia la pantalla de login.
  5. El usuario se loguea.
  6. El proveedor de autenticación válida las credenciales del usuario y el código de validación.
  7. El proveedor nos redirecciona a la url de retorno (app.com/myReturnUrl#temp_token=xxx) con el token temporal.
  8. Mediante el token temporal, la app obtiene el access_token.
  9. Se usa ese token junto al code-verifier generado anteriormente para hacer una petición al endpoint de token obtener el access-token (pocos minutos de caducidad) y refresh token (2h de caducidad).
  10. Se accede correctamente al API usando el access-token.

Cómo integrarse

Para integrar una aplicación con Nautilus hay que cumplir su protocolo:

Las peticiones enviadas desde el cliente al API tendrán un header llamado authorization que contendrá un token JWT (http://jwt.io). Este token estará firmado por el SSO de nautilus. La APP dispondrá de la clave pública para comprobar la firma. Si no existe el token, está caducado o es incorrecto el API deberá devolver 401 (NOT AUTHORIZED) y el Cliente (web) intentará refrescar el token o redirigirá a la página de login del SSO de nautilus si no pudiera refrescarlo.

La buena noticia es que hemos desarrollado algunas librerías que convierten esta integración en algo trivial.

Middleware node express para validar autenticación en el API

Para aplicaciones RP que utilicen la librería Express de NodeJs se puede utilizar el midleware @platform-node-tools/express-auth desarrollado exclusivamente para la validación y gestión de peticiones autenticadas.

javascript
//Ejemplo de uso
const express = require("express");
const tokenAuth = require("@platform-node-tools/express-auth");
const app = express();
app.use(
  tokenAuth.aquacisTokenAuth({
    publicKey: config.TOKEN_PUBLIC,
    excludePaths: ["/dashboard", "/version", "/health", "/"],
  })
);
//Ejemplo de uso
const express = require("express");
const tokenAuth = require("@platform-node-tools/express-auth");
const app = express();
app.use(
  tokenAuth.aquacisTokenAuth({
    publicKey: config.TOKEN_PUBLIC,
    excludePaths: ["/dashboard", "/version", "/health", "/"],
  })
);

Librería para hacer peticiones autenticadas desde el CLIENTE

Además para hacer peticiones autenticadas desde aplicaciones cliente en Javascript podemos utilizar la librería authFetch, un wrapper del fetch de Javascript que además de enviar el header authentication en sus peticiones, negocia de forma transparente la obtención del token con el SSO cuando no se tiene o ha caducado, redirigiendo al login sólo si el usuario no estuviera logueado (SSO):

Tenemos publicada una librería llamada nautilus-auth. Para instalarla debemos ejecutar npm install nautilus-auth. Dicha librería es únicamente compatible con el flujo de autenticación con PKCE (v2). Se exponen los siguientes métodos para una fácil integración:

  • authAxiosClient. Es un cliente de axios con el middleware configurado para poder usarlo como axios client en la aplicación.
  • getAuthFetch. Es un proxy del fetch de javascript, pero gestiona el refresco del token y la redirección al auth de Nautilus.
  • checkLogin. Comprueba si el usuario está logeado.
  • goToLogin. Redirige al login de Nautilus. Borra tokens del storage y genera un nuevo code verifier y un code challenge.
  • goToLogout. Redirige al logout de Nautilus y elimina los tokens del storage del navegador.
  • checkTempToken. Comprueba si tenemos el token en el fragment de la URL. En el caso que lo tenga, hace el intercambio de claves. (Deprecado)
  • initApp. Podemos pasar un objeto con las propiedades que queremos sobreescribir.
javascript
import auth from "nautilus-auth";

// Ejemplo de configuración
auth.initApp({
  clientUrl: "http://my-app.com",
  authUrl: "https://login.dev.nautilus.app",
});

// Ejemplo de uso de funciones
auth.authFetch("https://myurl.com", {
  method: "POST",
  body: {
    id: "1",
    description: "updated description",
  },
  json: true,
});

auth.checkLogin().then((logged) => {
  // Útil para guards
});

auth.goToLogout();

await auth.goToLogin();

const get = (url, config = {}) =>
  auth.authAxiosClient.get(url, config).then(({ data }) => data);

const post = (url, body = {}, config = {}) =>
  auth.authAxiosClient.post(url, body, config).then(({ data }) => data);

const put = (url, body = {}, config = {}) =>
  auth.authAxiosClient.put(url, body, config).then(({ data }) => data);

const _delete = (url, config = {}) =>
  auth.authAxiosClient.delete(url, config).then(({ data }) => data);
import auth from "nautilus-auth";

// Ejemplo de configuración
auth.initApp({
  clientUrl: "http://my-app.com",
  authUrl: "https://login.dev.nautilus.app",
});

// Ejemplo de uso de funciones
auth.authFetch("https://myurl.com", {
  method: "POST",
  body: {
    id: "1",
    description: "updated description",
  },
  json: true,
});

auth.checkLogin().then((logged) => {
  // Útil para guards
});

auth.goToLogout();

await auth.goToLogin();

const get = (url, config = {}) =>
  auth.authAxiosClient.get(url, config).then(({ data }) => data);

const post = (url, body = {}, config = {}) =>
  auth.authAxiosClient.post(url, body, config).then(({ data }) => data);

const put = (url, body = {}, config = {}) =>
  auth.authAxiosClient.put(url, body, config).then(({ data }) => data);

const _delete = (url, config = {}) =>
  auth.authAxiosClient.delete(url, config).then(({ data }) => data);

Otra forma de poner esos valores es a través de las variables de entorno window.env.AUTHSSO_URL y window.env.CLIENT_URL

Para la integración PKCE sin la librería nautilus-auth, ver siguiente página integración PKCE.

Para la integración de la versión anterior (con cookies), se deberá utilizar nuestra semilla React para proyectos frontend.

Autenticación (OIDC)

Para facilitar la integración con Nautilus, el proveedor de autenticación implementa el protocolo OpenId Connect.

Se puede encontrar la información para autodescubrimiento de integración con OpenId Connect en https://login.nautilus.app/.well-known/openid-configuration.

Enlaces de interés

Single Sign On (SSO)

La aplicación web puede pedir un token a nautilus (https://login.nautilus.app/refresh_token) mediante una petición sin necesidad de redirigir al usuario al login. Si el usuario no está logueado habría que redirigirlo a la web de login para que introduzca sus credenciales. Además en la ruta GET puede introducir un parámetro returnUrl especificando a dónde tiene que redirigirse al usuario después de logarse.

https://login.nautilus.app/login?&returnUrl=https://cx-issue.nautilus.app

Si no se introduce este parámetro será redirigido a la aplicación Portal de Nautilus donde el usuario tiene accesos directos a todas las aplicaciones integradas en Nautilus a las que tiene acceso.

Si el usuario ya estuviera logueado y a pesar de eso ha sido redirigido a login, el login lo redireccionará a la dirección que aparezca en el parámetro returnUrl sin necesidad de introducir los credenciales y de manera transparente para él.

Single Log Out (SLO)

Podemos desloguear al usuario de todas las aplicaciones redirigiéndolo a la siguiente URL.

https://login.nautilus.app/logout?returnUrl=https://myaccount.nautilus.app

Donde returnUrl al igual que en el caso anterior sería la página la que se debe devolver después de haber hecho el logout.

Autenticación de identidades digitales

Para consumir algunas APIs, como por ejemplo el API Público de Nautilus, necesitamos enviar un token que identifique nuestras peticiones. Este token llamado "Bearer token" debemos solicitarlo al proveedor de autenticación, en nuestro caso https://login.nautilus.app, en el endpoint /apiToken. Para ello debemos hacer una petición a este endpoint introduciendo un "Basic Token" que son los credenciales de quién hace la petición. Por ejemplo, si quisiéramos loguearnos para

  1. Entrar en el Portal Nautilus y crear un usuario de tipo identidad digital para la aplicación que quiere consumir el API. Añadir identidad digital
  2. Desde el Portal asegurarnos que la identidad digital todos los permisos necesarios para los recursos y acciones que se desean consumir.
  3. Obtener el Basic token de la identidad digital, que nos permitirá autenticarla.
  4. Obtener el Bearer token que permite a esa identidad digital consumir los servicios del API de Nautilus:
javascript
    GET https://login.nautilus.app/apiToken
    authorization: Basic YmIyMjI2OTQtMxU3OC00ZjNlLTk5ZjUtZDMzZjk2MTFhMjU3Ok59UCNcZllBUWo=
    GET https://login.nautilus.app/apiToken
    authorization: Basic YmIyMjI2OTQtMxU3OC00ZjNlLTk5ZjUtZDMzZjk2MTFhMjU3Ok59UCNcZllBUWo=
  1. El Bearer token obtenido es el que nos permitirá identificarnos en el API de Sentinel, así como otros apis que utilicen nuestro sistema de autenticación. Si el API nos devuelve error 401 puede que sea porque el token ha caducado y tendremos que repetir el proceso desde el punto 4.
javascript
    GET https://api.nautilus.app/profiles
    authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJTVVBFUl9BRE1JTiIsIm5iZiI6IjIwMTctMDUtMTZUMTY6MDA6MTUuOTYwWiIsImV4cCI6MTUyNjQ4NjQxNS45NTksImF1ZCI6ImFwaSIsInRva2VuVHlwZSI6IkFDQ0VTU19UT0tFTiIsImxvY2FsZSI6ImVzX0VTIiwidXNlck5hbWUiOiJTdXBlciBBZG1pbiIsInJvbGVzIjpbXX0.MycT6QoxZGDjn0owv5_vm1PGPdjRG60iFMdS_UdJhs_Ifgy4aUzIhfhgvSTURtqMeAMBaSigdgqb2oweyDqKf1vQSugbC19P0uJeOKGiaQuq2amtdU42fDpzs2hHouJ-Ffbtjxg4J25iCxm0Hrvb6EZxfbOtHJU_9r6ZwggBoc8
    GET https://api.nautilus.app/profiles
    authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJTVVBFUl9BRE1JTiIsIm5iZiI6IjIwMTctMDUtMTZUMTY6MDA6MTUuOTYwWiIsImV4cCI6MTUyNjQ4NjQxNS45NTksImF1ZCI6ImFwaSIsInRva2VuVHlwZSI6IkFDQ0VTU19UT0tFTiIsImxvY2FsZSI6ImVzX0VTIiwidXNlck5hbWUiOiJTdXBlciBBZG1pbiIsInJvbGVzIjpbXX0.MycT6QoxZGDjn0owv5_vm1PGPdjRG60iFMdS_UdJhs_Ifgy4aUzIhfhgvSTURtqMeAMBaSigdgqb2oweyDqKf1vQSugbC19P0uJeOKGiaQuq2amtdU42fDpzs2hHouJ-Ffbtjxg4J25iCxm0Hrvb6EZxfbOtHJU_9r6ZwggBoc8

En la siguiente imagen se puede ver el flujo de peticiones que tendremos que implementar en la aplicación que quiera consumir el API de Nautilus:

Diagrama autenticación de una identidad digital

  • Client: Sería la aplicación que queremos integrar con Nautilus.

  • RP: Sería el proveedor del recurso, en este caso el API de Nautilus https://api.nautilus.app

  • IDP: Sería el sistema de login de Nautilus, disponible en https://login.nautilus.app/apiToken

  • Paso 1: Se pide un recurso al API sin que estemos autenticados o con un Bearer token caducado.

  • Paso 2: El API nos devuelve error.

  • Paso 3: Pedimos al login un Bearer token enviando para ello un Basic token

  • Paso 4: Recibimos el Bearer token

  • Paso 5: Volvemos a hacer petición al API con un nuevo Bearer token

  • Paso 6: El API comprueba que estamos autorizados y nos envía el resultado de nuestra petición.