Autenticacion
La app implementa un sistema de autenticacion custom basado en JWT, sin depender de servicios externos como Clerk, Auth0 o Supabase. Toda la logica se concentra en el modulosrc/modules/auth/ y el cliente API en src/shared/services/api/.
Flujo de Autenticacion
- Login
- Registro
- Modo Visitor/Guest
- El usuario ingresa email y contrasena 2. Se llama a
authApi.login(email, password)3. La API devuelve:token,refreshToken,tokenExpiresIn, datos de usuario 4. Se calculatokenExpiry = Date.now() + tokenExpiresIn * 10005. Se almacenan tokens en SecureStore y datos de usuario en SecureStore 6. Se limpia el cache de tokens del API client (clearTokenCache) 7. Se actualiza elauthStoreconisAuthenticated: true8. Se identifica al usuario en PostHog analytics 9. Se inicializa la conexion a Stream Chat (no bloqueante) 10. Se invalidan todas las queries de React Query
Gestion de Tokens
Token Refresh Automatico
Cuando el access token expira, el sistema gestiona la renovacion automaticamente:Las requests que llegan durante el proceso de refresh se encolan en
requestQueue. Una vez
completado el refresh exitosamente, todas las requests encoladas se reintentan con el nuevo token.
refreshTokens() es single-flight: si ya hay un refresh en curso, las llamadas concurrentes
se unen a la promesa existente en lugar de gastar el mismo refresh token en paralelo.Resiliencia de Sesion
Un fallo durante el refresh ya no cierra la sesion automaticamente. El sistema distingue entre un rechazo real de la sesion y un fallo de transporte transitorio:Cuando se agotan los reintentos por fallos transitorios, la sesion se conserva y se marca en
memoria como
sessionUnverified: true (no se persiste). El hook useSessionResilience observa la
reconexion de red (offline→online) y el retorno de la app a primer plano, y llama a
verifySession() para re-confirmar la sesion en cuanto vuelve la conectividad. Un corte de red
nunca desemboca en un logout.Los endpoints de auth (
/auth/login, /auth/register, /auth/refresh-token) nunca disparan un
refresh cuando responden UNAUTHENTICATED (ver isAuthEndpoint). Incluir el propio
/auth/refresh-token evita un deadlock en el arranque en frio.Token Caching
El API client implementa un cache de token en memoria para evitar lecturas frecuentes a SecureStore:API Client
El cliente HTTP (src/shared/services/api/client.ts) esta construido sobre Axios con la siguiente configuracion:
Interceptors
Request Interceptor
- Agrega parametro
langa la URL segun idioma actual - Cambia
baseURLa chat backend siuseChatBackend: true - Obtiene token de auth y agrega header
Authorization: Bearer <token> - Respeta
requiresAuth: falseen headers para requests publicos
Response Interceptor
- Verifica el campo
codeen la respuesta de la API - Si
code !== SUCCESS, lanzaApiError - Si
code === UNAUTHENTICATED, inicia flujo de token refresh - Para errores de red (sin response), clasifica el tipo de fallo
Manejo de Errores
El error handler (src/shared/services/api/errorHandler.ts) clasifica los errores de red en categorias:
Todos los errores se reportan a Sentry con contexto adicional (endpoint, metodo, plataforma, diagnosticos de red).
Codigos de API
El sistema maneja los siguientes codigos de respuesta:Almacenamiento Seguro
- SecureStore (expo-secure-store)
- AsyncStorage
Datos cifrados en el dispositivo:
- Access token
- Refresh token
- Token expiry
- Datos de usuario (id, email, displayName, phone)
secureStorage en src/shared/services/storage/secureStorage.ts.Pantallas de Auth
Las pantallas de autenticacion se encuentran en el grupo(auth):
Inicializacion de Auth
Al iniciar la app,authStore.initializeAuth() ejecuta el siguiente flujo:
- Espera a que el store se hidrate desde almacenamiento persistido (con techo de 3s: si la hidratacion no reporta, continua igualmente)
- Verifica si hay tokens en el estado hidratado
- Si hay tokens pero estan expirados, intenta refresh automatico dentro de un presupuesto de 12s (
STARTUP_REFRESH_BUDGET_MS); si se excede, deja de esperar (no de refrescar), marca la sesion comosessionUnverifiedy libera el splash - Si no hay tokens en estado, busca directamente en SecureStore con techo de 5s por lectura (fallback)
- Si encuentra tokens validos, marca
isAuthenticated: truee identifica al usuario en analytics - Si no encuentra tokens, establece estado no autenticado
La inicializacion tiene un timeout de 15 segundos cuyo unico rol es liberar el spinner: ya no
destruye la sesion. Una API lenta tras un deploy (init >15s) solia cerrar la sesion sin que ningun
request hubiera sido rechazado; ahora se conservan
user, tokens e isAuthenticated. Los arranques
genuinamente colgados siguen cubiertos por los dos timeouts externos de 2 min
(useAppInitialization / useNavigation), que ademas reportan a Sentry que pasos quedaron
pendientes.Logout
El proceso de logout realiza las siguientes operaciones:- Llama a
authApi.logout()para invalidar tokens en el servidor - Limpia la cola de requests pendientes (
clearRequestQueue) - Reset de analytics (
analytics.reset()) - Limpia el estado del store
- Cancela y limpia todas las queries de React Query
- Desconecta y resetea el chat de Stream
- Limpia todos los datos de auth en SecureStore