fix: use cookie-based storage for Supabase client auth
Store auth session in cookies instead of localStorage so server-side code (admin layout, API routes, protected layout) can read the session. Implements chunked cookie support for large session tokens. https://claude.ai/code/session_01H2aRGDaKgarPvhay2HxN6Y
This commit is contained in:
@@ -1,9 +1,74 @@
|
||||
import { createClient as createSupabaseClient } from "@supabase/supabase-js";
|
||||
import type { Database } from "@/types/database.types";
|
||||
|
||||
// Client Supabase côté navigateur (composants client)
|
||||
// Storage basé sur les cookies pour que le serveur puisse lire la session
|
||||
// Remplace le localStorage par défaut de Supabase
|
||||
const cookieStorage = {
|
||||
getItem: (key: string): string | null => {
|
||||
if (typeof document === "undefined") return null;
|
||||
|
||||
// Essayer le cookie direct
|
||||
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const match = document.cookie.match(
|
||||
new RegExp(`(?:^|; )${escaped}=([^;]*)`)
|
||||
);
|
||||
if (match) return decodeURIComponent(match[1]);
|
||||
|
||||
// Essayer les cookies chunked (.0, .1, .2, ...)
|
||||
const chunks: string[] = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const chunkMatch = document.cookie.match(
|
||||
new RegExp(`(?:^|; )${escaped}\\.${i}=([^;]*)`)
|
||||
);
|
||||
if (chunkMatch) {
|
||||
chunks.push(decodeURIComponent(chunkMatch[1]));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (chunks.length > 0) return chunks.join("");
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
setItem: (key: string, value: string): void => {
|
||||
if (typeof document === "undefined") return;
|
||||
|
||||
// Supprimer les anciens cookies d'abord
|
||||
cookieStorage.removeItem(key);
|
||||
|
||||
const maxChunkSize = 3500; // Limite cookie ~4KB avec overhead
|
||||
|
||||
if (value.length <= maxChunkSize) {
|
||||
document.cookie = `${key}=${encodeURIComponent(value)}; path=/; max-age=${60 * 60 * 24 * 365}; SameSite=Lax`;
|
||||
} else {
|
||||
// Découper en chunks
|
||||
for (let i = 0; i * maxChunkSize < value.length; i++) {
|
||||
const chunk = value.substring(i * maxChunkSize, (i + 1) * maxChunkSize);
|
||||
document.cookie = `${key}.${i}=${encodeURIComponent(chunk)}; path=/; max-age=${60 * 60 * 24 * 365}; SameSite=Lax`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeItem: (key: string): void => {
|
||||
if (typeof document === "undefined") return;
|
||||
document.cookie = `${key}=; path=/; max-age=0`;
|
||||
for (let i = 0; i < 10; i++) {
|
||||
document.cookie = `${key}.${i}=; path=/; max-age=0`;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Client Supabase côté navigateur
|
||||
// Utilise les cookies comme storage pour que le serveur puisse lire la session
|
||||
export const createClient = () =>
|
||||
createSupabaseClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
auth: {
|
||||
storage: cookieStorage,
|
||||
flowType: "pkce",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user