sdk-simple-auth
Version:
Universal JavaScript/TypeScript authentication SDK with multi-backend support, automatic token refresh, and React integration
416 lines (355 loc) • 11.5 kB
JavaScript
/**
* Ejemplo de Uso con Axios y Interceptores Automáticos
*
* Este ejemplo muestra cómo configurar el SDK con tu instancia de Axios
* para que automáticamente:
* 1. Inyecte tokens en todas las peticiones
* 2. Detecte errores 401/422 y cierre sesión automáticamente
* 3. Intente refresh automático antes de cerrar sesión
*/
import { AuthSDK } from 'sdk-simple-auth';
import axios from 'axios';
// =====================================================
// CONFIGURACIÓN COMPLETA (Tu caso de uso)
// =====================================================
// 1. Crear instancia de Axios (SIN interceptores manuales)
const apiClient = axios.create({
baseURL: 'http://localhost:8000/api',
headers: {
'Content-Type': 'application/json',
},
});
// 2. Configurar AuthSDK con interceptores de Axios
const authSDK = new AuthSDK({
authServiceUrl: 'http://localhost:8000/api',
endpoints: {
login: '/login',
logout: '/logout',
refresh: '/refresh'
},
storage: {
type: 'indexedDB',
dbName: 'tps-intermotors',
storeName: 'auth',
dbVersion: 1,
tokenKey: 'tps-intermotors_auth_token',
userKey: 'tps-intermotors_auth_user',
refreshTokenKey: 'tps-intermotors_auth_refresh_token',
},
tokenRefresh: {
enabled: true,
bufferTime: 1800 // 30 minutos
},
sessionValidation: {
enabled: true,
validateOnFocus: true,
validateOnVisibility: true,
maxInactivityTime: 300, // 5 minutos
autoLogoutOnInvalid: true
},
// NUEVA CONFIGURACIÓN: Interceptores de Axios
interceptors: {
enabled: true, // ⚠️ IMPORTANTE: Activar interceptores
autoInjectToken: true, // Inyectar token automáticamente
handleAuthErrors: true, // Manejar 401/422 automáticamente
axiosInstance: apiClient // Tu instancia de Axios
}
}, {
// Callbacks
onLogin: (user, tokens) => {
console.log('✅ Login exitoso:', user.name);
},
onSessionInvalid: () => {
console.warn('❌ Sesión inválida detectada por interceptor');
// Redirigir al login
window.location.href = '/login?expired=true';
},
onTokenRefresh: (tokens) => {
console.log('🔄 Tokens refrescados automáticamente');
},
onError: (error) => {
console.error('❌ Error:', error);
}
});
// =====================================================
// AHORA TU apiClient YA TIENE INTERCEPTORES AUTOMÁTICOS
// =====================================================
// Ya NO necesitas esto:
/*
apiClient.interceptors.request.use(
async (config) => {
const token = await authSDK.getAccessToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}
);
*/
// El SDK ya lo hace automáticamente! 🎉
// =====================================================
// EJEMPLO DE USO
// =====================================================
// Login
async function login() {
try {
const user = await authSDK.login({
email: 'usuario@example.com',
password: 'password123'
});
console.log('Usuario logueado:', user);
return user;
} catch (error) {
console.error('Error en login:', error);
throw error;
}
}
// Hacer peticiones con apiClient (token inyectado automáticamente)
async function fetchProviders() {
try {
// ✅ Token se inyecta automáticamente
// ✅ Si el token expiró, intenta refresh automático
// ✅ Si el servidor retorna 401, cierra sesión y redirige
const response = await apiClient.get('/providers');
console.log('Proveedores:', response.data);
return response.data;
} catch (error) {
// Si llega aquí, es un error que NO es 401
// Los 401 se manejan automáticamente
console.error('Error obteniendo proveedores:', error);
throw error;
}
}
// Crear un proveedor
async function createProvider(data) {
try {
const response = await apiClient.post('/providers', data);
console.log('Proveedor creado:', response.data);
return response.data;
} catch (error) {
console.error('Error creando proveedor:', error);
throw error;
}
}
// =====================================================
// FLUJO COMPLETO DE EJEMPLO
// =====================================================
async function exampleFlow() {
console.log('=== Iniciando flujo de ejemplo ===\n');
// 1. Login
console.log('1️⃣ Haciendo login...');
await login();
// 2. Hacer peticiones normalmente
console.log('\n2️⃣ Obteniendo proveedores...');
await fetchProviders();
// 3. Simular que el token expira en el servidor
console.log('\n3️⃣ [Simulación] Token expira en el servidor...');
console.log(' (En tu backend, el token fue revocado o expiró)');
// 4. Intentar hacer otra petición
console.log('\n4️⃣ Intentando obtener proveedores de nuevo...');
try {
await fetchProviders();
} catch (error) {
// El interceptor detectará el 401 automáticamente
console.log('\n📊 Resultado:');
console.log(' ✅ Interceptor detectó 401');
console.log(' ✅ Intentó refresh automático');
console.log(' ✅ Refresh falló (token inválido)');
console.log(' ✅ Sesión cerrada automáticamente');
console.log(' ✅ Redirigido a /login');
}
}
// =====================================================
// VENTAJAS DE USAR INTERCEPTORES
// =====================================================
/*
❌ ANTES (Sin interceptores):
- Tenías que agregar manualmente el token en cada petición
- Si el token expiraba, seguía intentando peticiones
- Tenías que manejar manualmente errores 401 en cada componente
- La sesión persistía incluso con tokens inválidos
✅ AHORA (Con interceptores):
- Token se inyecta automáticamente en TODAS las peticiones
- Detecta 401 automáticamente en CUALQUIER petición
- Cierra sesión local cuando el servidor rechaza el token
- Intenta refresh automático antes de cerrar sesión
- Código más limpio y centralizado
*/
// =====================================================
// COMPARACIÓN DE CÓDIGO
// =====================================================
// ANTES: Tenías que hacer esto en CADA petición
async function fetchProviders_OLD() {
const token = await authSDK.getAccessToken();
try {
const response = await apiClient.get('/providers', {
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data;
} catch (error) {
if (error.response?.status === 401) {
// Manejar manualmente
await authSDK.logout();
window.location.href = '/login';
}
throw error;
}
}
// AHORA: Simple y limpio
async function fetchProviders_NEW() {
const response = await apiClient.get('/providers');
return response.data;
// ¡Eso es todo! El resto se maneja automáticamente
}
// =====================================================
// DEBUGGING
// =====================================================
// Ver estado de los interceptores
function debugInterceptors() {
console.log('\n🔍 Debug de Interceptores:');
console.log('Interceptor Manager:', authSDK.axiosInterceptorManager);
if (authSDK.axiosInterceptorManager) {
const status = authSDK.axiosInterceptorManager.getStatus();
console.log('Estado:', status);
console.log(' - Activo:', status.isActive);
console.log(' - Request Interceptor:', status.hasRequestInterceptor);
console.log(' - Response Interceptor:', status.hasResponseInterceptor);
} else {
console.log('⚠️ Interceptores no configurados');
}
}
// =====================================================
// CASOS DE USO COMUNES
// =====================================================
// Caso 1: Petición GET simple
async function getUsers() {
// Token inyectado automáticamente
const { data } = await apiClient.get('/users');
return data;
}
// Caso 2: Petición POST con datos
async function createUser(userData) {
// Token inyectado automáticamente
const { data } = await apiClient.post('/users', userData);
return data;
}
// Caso 3: Petición con parámetros
async function searchProducts(filters) {
// Token inyectado automáticamente
const { data } = await apiClient.get('/products', {
params: filters
});
return data;
}
// Caso 4: Upload de archivo
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
// Token inyectado automáticamente
const { data } = await apiClient.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
return data;
}
// =====================================================
// CONFIGURACIÓN PARA DIFERENTES ESCENARIOS
// =====================================================
// Escenario 1: Solo inyección de token (sin manejo de errores)
const authSDK_OnlyInject = new AuthSDK({
authServiceUrl: 'http://localhost:8000/api',
interceptors: {
enabled: true,
autoInjectToken: true,
handleAuthErrors: false, // Manejar errores manualmente
axiosInstance: apiClient
}
});
// Escenario 2: Solo manejo de errores (sin inyección automática)
const authSDK_OnlyErrors = new AuthSDK({
authServiceUrl: 'http://localhost:8000/api',
interceptors: {
enabled: true,
autoInjectToken: false, // Inyectar token manualmente
handleAuthErrors: true,
axiosInstance: apiClient
}
});
// Escenario 3: Todo automático (Recomendado)
const authSDK_Full = new AuthSDK({
authServiceUrl: 'http://localhost:8000/api',
interceptors: {
enabled: true,
autoInjectToken: true,
handleAuthErrors: true,
axiosInstance: apiClient
}
});
// =====================================================
// EXPORTAR PARA USO EN TU APP
// =====================================================
export {
authSDK,
apiClient,
login,
fetchProviders,
createProvider,
debugInterceptors,
getUsers,
createUser,
searchProducts,
uploadFile
};
// =====================================================
// INSTRUCCIONES DE USO EN TU APP
// =====================================================
/*
PASO 1: En tu archivo de configuración del SDK (ej: src/services/sdk-simple-auth.js)
import { AuthSDK } from 'sdk-simple-auth';
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'http://localhost:8000/api',
headers: { 'Content-Type': 'application/json' }
});
const authSDK = new AuthSDK({
authServiceUrl: 'http://localhost:8000/api',
endpoints: {
login: '/login',
logout: '/logout',
refresh: '/refresh'
},
interceptors: {
enabled: true,
autoInjectToken: true,
handleAuthErrors: true,
axiosInstance: apiClient
}
}, {
onSessionInvalid: () => {
window.location.href = '/login?expired=true';
}
});
export { authSDK, apiClient };
---
PASO 2: En tus componentes, usa apiClient directamente
import { apiClient } from '@/services/sdk-simple-auth';
async function fetchData() {
// ¡Token automático! ¡Manejo de 401 automático!
const { data } = await apiClient.get('/providers');
return data;
}
---
PASO 3: ¡Disfruta de código más limpio!
Ya NO necesitas:
❌ Agregar manualmente Authorization headers
❌ Verificar tokens en cada petición
❌ Manejar 401 en cada componente
❌ Preocuparte por sesiones inválidas
Todo se maneja automáticamente! ✅
*/
console.log('\n✨ Ejemplo de Axios Interceptors cargado\n');
console.log('📖 Lee los comentarios del código para ver cómo funciona');
console.log('🧪 Ejecuta exampleFlow() para ver el flujo completo\n');