¿Qué es la actualización sin interrupciones y cómo implementarla?

La actualización sin interrupciones es un mecanismo que permite a las aplicaciones frontend solicitar automáticamente nuevos tokens cuando el token actual está a punto de expirar, sin requerir intervención del usuario. Este enfoque mejora la experiencia del usuario y evita interrupciones en la sesión debido a la expiración del token.

Métodos Comunes para Implementar Actualización Sin Interrupciones

Gestión del Tiempo de Expiración del Token

  • Después de que el usuario inicia sesión, la aplicación frontend generalmente almacena el token de acceso (como JWT) y el token de actualización.
  • El token de acceso suele tener un período de validez corto (por ejemplo, 15 minutos), mientras que el token de actualización tiene una validez más prolongada (por ejemplo, 7 días).
  • La aplicación frontend solicita activamente un nuevo token de acceso usando el token de actualización cuando el token de acceso está a punto de expirar (por ejemplo, cuando quedan 2 minutos).

Interceptor

  • La aplicación frontend puede usar interceptores (como en Axios o Fetch) para interceptar todas las solicitudes.
  • Si se detecta que el token de acceso actual ha expirado, el interceptor primero usa el token de actualización para obtener un nuevo token de acceso y luego reenvía la solicitud original.
  • De esta manera, el usuario no percibe ninguna interrupción y la aplicación mantiene la operación continua.

Lógica de Actualización Sin Interrupciones

  • Configurar un temporizador para activar automáticamente la operación de actualización antes de que el token esté a punto de expirar.
  • Verificar periódicamente el período de validez del token y actualizarlo automáticamente si está a punto de expirar, para evitar interrupciones en la operación del usuario.
  • Si el token de actualización también ha expirado, redirigir al usuario a la página de inicio de sesión.

Autenticación Silenciosa

  • Para algunas aplicaciones frontend, se puede usar un iFrame oculto para realizar la autenticación silenciosa, utilizando el mecanismo de SSO para completar la actualización del token en segundo plano sin afectar la operación del usuario en la interfaz principal.

Ejemplo de Implementación de Interceptor en Axios

A continuación se muestra un ejemplo completo de implementación de un interceptor de Axios para manejar la actualización automática de tokens JWT y reintentos de solicitudes. En este ejemplo, se supone que ya tienes una API backend que proporciona la funcionalidad de actualización de tokens.

1. Crear una Instancia de Axios

Primero, necesitamos crear una instancia de Axios y configurar los interceptores de solicitudes y respuestas.

1
import axios from "axios";
2
3
// Crear instancia de Axios
4
const apiClient = axios.create({
5
baseURL: "https://api.example.com", // Reemplaza con tu URL base de API
6
timeout: 10000,
7
});

2. Añadir Interceptor de Solicitudes

Añadir el encabezado de Authorization en cada solicitud para incluir el token de acceso JWT.

1
// Añadir interceptor de solicitudes
2
apiClient.interceptors.request.use(
3
(config) => {
4
// Incluir el encabezado Authorization en cada solicitud
5
const token = localStorage.getItem("token");
6
if (token) {
7
config.headers["Authorization"] = `Bearer ${token}`;
8
}
9
return config;
10
},
11
(error) => {
12
// Manejar errores de solicitud
13
return Promise.reject(error);
14
},
15
);

3. Añadir Interceptor de Respuestas

Manejar los errores 401 y usar el token de actualización para obtener un nuevo token de acceso cuando el token expira.

1
// Añadir interceptor de respuestas
2
apiClient.interceptors.response.use(
3
(response) => {
4
// Retornar directamente los datos de la respuesta
5
return response;
6
},
7
async (error) => {
8
const originalRequest = error.config;
9
10
// Si el código de estado de la respuesta es 401 y la solicitud original no se ha reintentado
11
if (
12
error.response &&
13
error.response.status === 401 &&
14
!originalRequest._retry
15
) {
16
originalRequest._retry = true;
17
try {
18
const refreshToken = localStorage.getItem("refreshToken");
19
if (refreshToken) {
20
// Enviar solicitud de token de actualización
21
const { data } = await axios.post(
22
"https://api.example.com/auth/refresh",
23
{ token: refreshToken },
24
);
25
26
// Actualizar el token almacenado localmente
27
localStorage.setItem("token", data.token);
28
29
// Actualizar el encabezado Authorization
30
axios.defaults.headers.common["Authorization"] =
31
`Bearer ${data.token}`;
32
33
// Reenviar la solicitud original
34
originalRequest.headers["Authorization"] = `Bearer ${data.token}`;
35
return apiClient(originalRequest);
36
}
37
} catch (refreshError) {
38
// Si el token de actualización también ha expirado, redirigir a la página de inicio de sesión
39
localStorage.removeItem("token");
40
localStorage.removeItem("refreshToken");
41
window.location.href = "/login";
42
}
43
}
44
45
// Manejar otros errores
46
return Promise.reject(error);
47
},
48
);
49
50
export default apiClient;

Explicación del Código

  1. Instanciación de Axios:

    Se utiliza axios.create() para crear una instancia personalizada de Axios apiClient, que puede tener una URL base y otras configuraciones.

  2. Interceptor de Solicitudes:

    Antes de que se envíe cada solicitud, se verifica si existe un token de acceso JWT. Si existe, se agrega al encabezado Authorization de la solicitud.

  3. Interceptor de Respuestas:

    • Manejo de Errores 401: Cuando el servidor devuelve un error 401, esto indica que el token podría haber expirado.
    • Actualización del Token: Si existe un token de actualización, se envía una solicitud al endpoint de la API para obtener un nuevo token de acceso.
    • Actualización del Token: El nuevo token se almacena localmente y se actualizan los encabezados de solicitudes de Axios para usar el nuevo token en solicitudes futuras.
    • Reintento de Solicitud: La solicitud original se reenvía utilizando el nuevo token.
  4. Fallo en la Actualización del Token:

    Si el token de actualización también es inválido o ha expirado, se eliminan los tokens almacenados localmente y se redirige al usuario a la página de inicio de sesión.

Cómo Usar

En la aplicación, puedes usar apiClient en lugar del Axios original para enviar solicitudes HTTP:

1
import apiClient from "./apiClient";
2
3
async function getUserData() {
4
try {
5
const response = await apiClient.get("/user/profile");
6
console.log(response.data);
7
} catch (error) {
8
console.error("Error al obtener los datos del usuario:", error);
9
}
10
}

Este código utiliza el apiClient encapsulado para enviar solicitudes, manejando automáticamente la actualización y reintento del token.

Conclusión

Con los métodos descritos, puedes implementar la actualización sin interrupciones en aplicaciones frontend, asegurando que los usuarios no sean interrumpidos debido a la expiración del token. Este mecanismo mejora la experiencia del usuario y hace que la aplicación sea más fluida.