UNPKG

@supabase/ssr

Version:

Use the Supabase JavaScript library in popular server-side rendering (SSR) frameworks.

80 lines (71 loc) 2.45 kB
import type { CookieOptions, GetAllCookies, SetAllCookies } from "./types"; import { DEFAULT_COOKIE_OPTIONS, isChunkLike } from "./utils"; /** * One-shot helper to clear Supabase auth cookies at one or more explicit * scopes. Use after a deploy that changes cookie `Domain`, `Path`, or other * scope-affecting options, to remove stale cookies that the runtime `signOut` * cannot reach because they live at a different scope. * * The helper issues a `Set-Cookie` with `Max-Age=0` for every known chunk of * the given `storageKey` at each scope. The browser silently ignores * `Set-Cookie` attempts for scopes the current host doesn't own, so passing * more scopes than necessary is safe — only the ones that actually held * stale cookies will have any observable effect. * * For the common host-only -> parent-domain migration, this helper is not * required: `signOut` already clears the host-only counterpart automatically * when `cookieOptions.domain` is set on the current client. * * @example * // After migrating from `.foo.com` to `.bar.com`: * await clearAuthCookiesAtScopes({ * getAll, * setAll, * storageKey: 'sb-<project-ref>-auth-token', * scopes: [{ domain: '.foo.com' }], * }); * * @example * // Path migration from `/app` to `/`: * await clearAuthCookiesAtScopes({ * getAll, * setAll, * storageKey: 'sb-<project-ref>-auth-token', * scopes: [{ path: '/app' }], * }); * * @category Cookies */ export async function clearAuthCookiesAtScopes(input: { getAll: (keyHints: string[]) => ReturnType<GetAllCookies>; setAll: SetAllCookies; storageKey: string; scopes: Array<Partial<CookieOptions>>; }): Promise<void> { const { getAll, setAll, storageKey, scopes } = input; if (scopes.length === 0) { return; } const allCookies = (await getAll([storageKey])) ?? []; const chunkNames = allCookies .map(({ name }) => name) .filter((name) => isChunkLike(name, storageKey)); if (chunkNames.length === 0) { return; } const toSet = scopes.flatMap((scope) => { const cookieOptions = { ...DEFAULT_COOKIE_OPTIONS, ...scope, maxAge: 0, }; // Same NextJS cookieStore guard as createStorageFromOptions. delete (cookieOptions as { name?: string }).name; return chunkNames.map((name) => ({ name, value: "", options: cookieOptions, })); }); await setAll(toSet, {}); }