diff --git a/client/src/_core/hooks/useAuth.ts b/client/src/_core/hooks/useAuth.ts index dcef9bd..9a63901 100644 --- a/client/src/_core/hooks/useAuth.ts +++ b/client/src/_core/hooks/useAuth.ts @@ -36,6 +36,8 @@ export function useAuth(options?: UseAuthOptions) { } throw error; } finally { + // Supprimer le token de localStorage + localStorage.removeItem('auth_token'); utils.auth.me.setData(undefined, null); await utils.auth.me.invalidate(); } diff --git a/client/src/main.tsx b/client/src/main.tsx index 8adf6f5..67e518e 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -43,9 +43,22 @@ const trpcClient = trpc.createClient({ url: "/api/trpc", transformer: superjson, fetch(input, init) { + // Récupérer le token depuis localStorage + const token = localStorage.getItem('auth_token'); + + const headers: HeadersInit = { + ...(init?.headers || {}), + }; + + // Ajouter le header Authorization si un token existe + if (token) { + headers['Authorization'] = `Bearer ${token}`; + } + return globalThis.fetch(input, { ...(init ?? {}), credentials: "include", + headers, }); }, }), diff --git a/client/src/pages/Login.tsx b/client/src/pages/Login.tsx index d3768ad..928cf3e 100644 --- a/client/src/pages/Login.tsx +++ b/client/src/pages/Login.tsx @@ -16,7 +16,11 @@ export default function Login() { const [error, setError] = useState(""); const loginMutation = trpc.auth.login.useMutation({ - onSuccess: () => { + onSuccess: (data) => { + // Stocker le token dans localStorage + if (data.token) { + localStorage.setItem('auth_token', data.token); + } // Rediriger vers le tableau de bord admin window.location.href = "/admin"; }, diff --git a/client/src/pages/Register.tsx b/client/src/pages/Register.tsx index 63ee3a3..2e80e81 100644 --- a/client/src/pages/Register.tsx +++ b/client/src/pages/Register.tsx @@ -18,7 +18,11 @@ export default function Register() { const [error, setError] = useState(""); const registerMutation = trpc.auth.register.useMutation({ - onSuccess: () => { + onSuccess: (data) => { + // Stocker le token dans localStorage + if (data.token) { + localStorage.setItem('auth_token', data.token); + } // Rediriger vers le tableau de bord window.location.href = "/"; }, diff --git a/server/_core/context.ts b/server/_core/context.ts index be6955f..744496d 100644 --- a/server/_core/context.ts +++ b/server/_core/context.ts @@ -16,8 +16,16 @@ export async function createContext( let user: User | null = null; try { - // Récupérer le token JWT depuis le cookie - const token = opts.req.cookies[COOKIE_NAME]; + // Essayer de récupérer le token depuis le cookie d'abord + let token = opts.req.cookies[COOKIE_NAME]; + + // Si pas de cookie, essayer le header Authorization + if (!token) { + const authHeader = opts.req.headers.authorization; + if (authHeader && authHeader.startsWith('Bearer ')) { + token = authHeader.substring(7); + } + } if (token) { // Vérifier et décoder le token diff --git a/server/routers.ts b/server/routers.ts index 6c7302e..66867ec 100644 --- a/server/routers.ts +++ b/server/routers.ts @@ -57,7 +57,7 @@ export const appRouter = router({ const cookieOptions = getSessionCookieOptions(ctx.req); ctx.res.cookie(COOKIE_NAME, token, { ...cookieOptions, maxAge: 30 * 24 * 60 * 60 * 1000 }); // 30 jours - return { success: true, userId }; + return { success: true, userId, token }; }), login: publicProcedure @@ -86,9 +86,7 @@ export const appRouter = router({ } // Vérifier le mot de passe - console.log('[LOGIN] Verifying password for:', user.email); const isValid = await verifyPassword(input.password, user.password); - console.log('[LOGIN] Password valid:', isValid); if (!isValid) { throw new TRPCError({ code: 'UNAUTHORIZED', message: 'Email ou mot de passe incorrect' }); } @@ -103,7 +101,7 @@ export const appRouter = router({ const cookieOptions = getSessionCookieOptions(ctx.req); ctx.res.cookie(COOKIE_NAME, token, { ...cookieOptions, maxAge: 30 * 24 * 60 * 60 * 1000 }); // 30 jours - return { success: true, user: { id: user.id, email: user.email, name: user.name, role: user.role } }; + return { success: true, user: { id: user.id, email: user.email, name: user.name, role: user.role }, token }; }), logout: publicProcedure.mutation(({ ctx }) => { diff --git a/todo.md b/todo.md index 0521ec2..f072830 100644 --- a/todo.md +++ b/todo.md @@ -273,3 +273,20 @@ - [x] Vérifier que le contexte tRPC récupère correctement l'utilisateur depuis le cookie - [x] Corriger le problème de redirection (redirection directe vers /admin au lieu de /) - [x] Tester la connexion complète + +## Correction vérification de session après connexion + +- [ ] Diagnostiquer pourquoi la session n'est pas reconnue après connexion +- [ ] Vérifier que le cookie est correctement défini et lu +- [ ] Vérifier la logique de vérification JWT dans le contexte tRPC +- [ ] Corriger la vérification de session +- [ ] Tester la connexion complète avec vérification de session + +## Implémentation authentification hybride (cookies + Authorization header) + +- [x] Modifier le contexte tRPC pour lire le token depuis le header Authorization en plus des cookies +- [x] Modifier les procédures login/register pour retourner le token au client +- [x] Stocker le token dans localStorage côté client +- [x] Modifier le client tRPC pour envoyer le token dans le header Authorization +- [x] Tester la connexion dans l'environnement de preview Manus +- [x] Vérifier que la solution fonctionne aussi en production