New token arch

This commit is contained in:
Urtzi Alfaro
2026-01-10 21:45:37 +01:00
parent cc53037552
commit bf1db7cb9e
26 changed files with 1751 additions and 107 deletions

View File

@@ -1,6 +1,8 @@
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { GLOBAL_USER_ROLES, type GlobalUserRole } from '../types/roles';
import { getSubscriptionFromJWT, getTenantAccessFromJWT, getPrimaryTenantIdFromJWT, JWTSubscription } from '../utils/jwt';
import { JWTSubscription as JWTSubscriptionType } from '../utils/jwt';
export interface User {
id: string;
@@ -26,6 +28,14 @@ export interface AuthState {
isAuthenticated: boolean;
isLoading: boolean;
error: string | null;
jwtSubscription: JWTSubscription | null;
jwtTenantAccess: Array<{
id: string;
role: string;
tier: string;
}> | null;
primaryTenantId: string | null;
subscription_from_jwt?: boolean;
// Actions
login: (email: string, password: string) => Promise<void>;
@@ -43,7 +53,7 @@ export interface AuthState {
updateUser: (updates: Partial<User>) => void;
clearError: () => void;
setLoading: (loading: boolean) => void;
setDemoAuth: (token: string, demoUser: Partial<User>) => void;
setDemoAuth: (token: string, demoUser: Partial<User>, subscriptionTier?: string) => void;
// Permission helpers
hasPermission: (permission: string) => boolean;
@@ -78,6 +88,11 @@ export const useAuthStore = create<AuthState>()(
apiClient.setRefreshToken(response.refresh_token);
}
// NEW: Extract subscription from JWT
const jwtSubscription = getSubscriptionFromJWT(response.access_token);
const jwtTenantAccess = getTenantAccessFromJWT(response.access_token);
const primaryTenantId = getPrimaryTenantIdFromJWT(response.access_token);
set({
user: response.user || null,
token: response.access_token,
@@ -85,6 +100,9 @@ export const useAuthStore = create<AuthState>()(
isAuthenticated: true,
isLoading: false,
error: null,
jwtSubscription,
jwtTenantAccess,
primaryTenantId,
});
} else {
throw new Error('Login failed');
@@ -192,12 +210,23 @@ export const useAuthStore = create<AuthState>()(
apiClient.setRefreshToken(response.refresh_token);
}
// NEW: Extract FRESH subscription from new JWT
const jwtSubscription = getSubscriptionFromJWT(response.access_token);
const jwtTenantAccess = getTenantAccessFromJWT(response.access_token);
const primaryTenantId = getPrimaryTenantIdFromJWT(response.access_token);
set({
token: response.access_token,
refreshToken: response.refresh_token || refreshToken,
isLoading: false,
error: null,
// NEW: Update subscription from fresh JWT
jwtSubscription,
jwtTenantAccess,
primaryTenantId,
});
console.log('Auth refreshed with new subscription:', jwtSubscription?.tier);
} else {
throw new Error('Token refresh failed');
}
@@ -231,12 +260,19 @@ export const useAuthStore = create<AuthState>()(
set({ isLoading: loading });
},
setDemoAuth: (token: string, demoUser: Partial<User>) => {
setDemoAuth: (token: string, demoUser: Partial<User>, subscriptionTier?: string) => {
console.log('🔧 [Auth Store] setDemoAuth called - demo sessions use X-Demo-Session-Id header, not JWT');
// DO NOT set API client token for demo sessions!
// Demo authentication works via X-Demo-Session-Id header, not JWT
// The demo middleware handles authentication server-side
// NEW: Create synthetic JWT subscription data for demo sessions
const jwtSubscription = subscriptionTier ? {
tier: subscriptionTier as 'starter' | 'professional' | 'enterprise',
status: 'active' as const,
valid_until: null
} : null;
// Update store state so user is marked as authenticated
set({
token: null, // No JWT token for demo sessions
@@ -245,8 +281,10 @@ export const useAuthStore = create<AuthState>()(
isAuthenticated: true, // User is authenticated via demo session
isLoading: false,
error: null,
jwtSubscription, // NEW: Set subscription data for demo sessions
subscription_from_jwt: true, // NEW: Flag to indicate subscription is from JWT
});
console.log('✅ [Auth Store] Demo auth state updated (no JWT token)');
console.log('✅ [Auth Store] Demo auth state updated (no JWT token)', { subscriptionTier });
},
// Permission helpers - Global user permissions only
@@ -323,6 +361,9 @@ export const useAuthUser = () => useAuthStore((state) => state.user);
export const useIsAuthenticated = () => useAuthStore((state) => state.isAuthenticated);
export const useAuthLoading = () => useAuthStore((state) => state.isLoading);
export const useAuthError = () => useAuthStore((state) => state.error);
export const useJWTSubscription = () => useAuthStore((state) => state.jwtSubscription);
export const useJWTTenantAccess = () => useAuthStore((state) => state.jwtTenantAccess);
export const usePrimaryTenantId = () => useAuthStore((state) => state.primaryTenantId);
export const usePermissions = () => useAuthStore((state) => ({
hasPermission: state.hasPermission,
hasRole: state.hasRole,