diff --git a/.changeset/silly-beds-watch.md b/.changeset/silly-beds-watch.md new file mode 100644 index 00000000..3bad1335 --- /dev/null +++ b/.changeset/silly-beds-watch.md @@ -0,0 +1,8 @@ +--- +'@supabase/auth-helpers-nextjs': patch +'@supabase/auth-helpers-remix': patch +'@supabase/auth-helpers-shared': patch +'@supabase/auth-helpers-sveltekit': patch +--- + +simplifying defaults for storage adapter diff --git a/packages/nextjs/src/browserClient.ts b/packages/nextjs/src/browserClient.ts index 1d28bcad..0eb0f0cd 100644 --- a/packages/nextjs/src/browserClient.ts +++ b/packages/nextjs/src/browserClient.ts @@ -1,10 +1,9 @@ import { BrowserCookieAuthStorageAdapter, - CookieOptions, - DEFAULT_COOKIE_OPTIONS, - SupabaseClientOptionsWithoutAuth + CookieOptionsWithName, + SupabaseClientOptionsWithoutAuth, + createSupabaseClient } from '@supabase/auth-helpers-shared'; -import { createClient } from '@supabase/supabase-js'; export function createBrowserSupabaseClient< Database = any, @@ -20,7 +19,7 @@ export function createBrowserSupabaseClient< supabaseUrl?: string; supabaseKey?: string; options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; } = {}) { if (!supabaseUrl || !supabaseKey) { throw new Error( @@ -28,7 +27,7 @@ export function createBrowserSupabaseClient< ); } - return createClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, @@ -38,19 +37,8 @@ export function createBrowserSupabaseClient< } }, auth: { - flowType: 'pkce', - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new BrowserCookieAuthStorageAdapter({ - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }) + storageKey: cookieOptions?.name, + storage: new BrowserCookieAuthStorageAdapter(cookieOptions) } }); } diff --git a/packages/nextjs/src/middlewareClient.ts b/packages/nextjs/src/middlewareClient.ts index c2e80edb..873ad73f 100644 --- a/packages/nextjs/src/middlewareClient.ts +++ b/packages/nextjs/src/middlewareClient.ts @@ -1,20 +1,20 @@ import { CookieAuthStorageAdapter, CookieOptions, - DEFAULT_COOKIE_OPTIONS, + CookieOptionsWithName, + createSupabaseClient, parseCookies, serializeCookie, SupabaseClientOptionsWithoutAuth } from '@supabase/auth-helpers-shared'; -import { createClient, SupabaseClientOptions } from '@supabase/supabase-js'; import { NextRequest, NextResponse } from 'next/server'; class NextMiddlewareAuthStorageAdapter extends CookieAuthStorageAdapter { constructor( private readonly context: { req: NextRequest; res: NextResponse }, - private readonly cookieOptions?: CookieOptions + cookieOptions?: CookieOptions ) { - super(); + super(cookieOptions); } protected getCookie(name: string): string | null | undefined { @@ -59,7 +59,7 @@ export function createMiddlewareSupabaseClient< supabaseUrl?: string; supabaseKey?: string; options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; } = {} ) { if (!supabaseUrl || !supabaseKey) { @@ -68,7 +68,7 @@ export function createMiddlewareSupabaseClient< ); } - return createClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, @@ -78,21 +78,8 @@ export function createMiddlewareSupabaseClient< } }, auth: { - flowType: 'pkce', - autoRefreshToken: false, - detectSessionInUrl: false, - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new NextMiddlewareAuthStorageAdapter(context, { - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }) + storageKey: cookieOptions?.name, + storage: new NextMiddlewareAuthStorageAdapter(context, cookieOptions) } }); } diff --git a/packages/nextjs/src/serverClient.ts b/packages/nextjs/src/serverClient.ts index dd8832ea..8bcd3a84 100644 --- a/packages/nextjs/src/serverClient.ts +++ b/packages/nextjs/src/serverClient.ts @@ -1,12 +1,12 @@ import { CookieAuthStorageAdapter, CookieOptions, - DEFAULT_COOKIE_OPTIONS, + CookieOptionsWithName, + createSupabaseClient, parseCookies, serializeCookie, SupabaseClientOptionsWithoutAuth } from '@supabase/auth-helpers-shared'; -import { createClient } from '@supabase/supabase-js'; import { GetServerSidePropsContext, NextApiRequest, @@ -19,9 +19,9 @@ class NextServerAuthStorageAdapter extends CookieAuthStorageAdapter { private readonly context: | GetServerSidePropsContext | { req: NextApiRequest; res: NextApiResponse }, - private readonly cookieOptions?: CookieOptions + cookieOptions?: CookieOptions ) { - super(); + super(cookieOptions); } protected getCookie(name: string): string | null | undefined { @@ -79,7 +79,7 @@ export function createServerSupabaseClient< supabaseUrl?: string; supabaseKey?: string; options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; } = {} ) { if (!supabaseUrl || !supabaseKey) { @@ -88,7 +88,7 @@ export function createServerSupabaseClient< ); } - return createClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, @@ -98,21 +98,8 @@ export function createServerSupabaseClient< } }, auth: { - flowType: 'pkce', - autoRefreshToken: false, - detectSessionInUrl: false, - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new NextServerAuthStorageAdapter(context, { - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }) + storageKey: cookieOptions?.name, + storage: new NextServerAuthStorageAdapter(context, cookieOptions) } }); } diff --git a/packages/nextjs/src/serverComponentClient.ts b/packages/nextjs/src/serverComponentClient.ts index c2b61cd0..bd5ca49d 100644 --- a/packages/nextjs/src/serverComponentClient.ts +++ b/packages/nextjs/src/serverComponentClient.ts @@ -1,19 +1,19 @@ import { CookieAuthStorageAdapter, CookieOptions, - DEFAULT_COOKIE_OPTIONS, - SupabaseClientOptionsWithoutAuth + CookieOptionsWithName, + SupabaseClientOptionsWithoutAuth, + createSupabaseClient } from '@supabase/auth-helpers-shared'; -import { createClient } from '@supabase/supabase-js'; class NextServerComponentAuthStorageAdapter extends CookieAuthStorageAdapter { constructor( private readonly context: { cookies: () => any; // TODO update this to be ReadonlyHeaders when we upgrade to Next.js 13 }, - private readonly cookieOptions?: CookieOptions + cookieOptions?: CookieOptions ) { - super(); + super(cookieOptions); } protected getCookie(name: string): string | null | undefined { @@ -53,7 +53,7 @@ export function createServerComponentSupabaseClient< supabaseUrl?: string; supabaseKey?: string; options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; } = {} ) { if (!supabaseUrl || !supabaseKey) { @@ -62,7 +62,7 @@ export function createServerComponentSupabaseClient< ); } - return createClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, @@ -72,21 +72,8 @@ export function createServerComponentSupabaseClient< } }, auth: { - flowType: 'pkce', - autoRefreshToken: false, - detectSessionInUrl: false, - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new NextServerComponentAuthStorageAdapter(context, { - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }) + storageKey: cookieOptions?.name, + storage: new NextServerComponentAuthStorageAdapter(context, cookieOptions) } }); } diff --git a/packages/nextjs/src/types.ts b/packages/nextjs/src/types.ts deleted file mode 100644 index 6c50b7ca..00000000 --- a/packages/nextjs/src/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type AddParameters< - TFunction extends (...args: any) => any, - TParameters extends [...args: any] -> = ( - ...args: [...Parameters, ...TParameters] -) => ReturnType; diff --git a/packages/remix/src/createSupabaseClient.ts b/packages/remix/src/createSupabaseClient.ts index 646b9e11..a693f72a 100644 --- a/packages/remix/src/createSupabaseClient.ts +++ b/packages/remix/src/createSupabaseClient.ts @@ -2,12 +2,13 @@ import { BrowserCookieAuthStorageAdapter, CookieAuthStorageAdapter, CookieOptions, - DEFAULT_COOKIE_OPTIONS, + CookieOptionsWithName, + createSupabaseClient, parseCookies, serializeCookie, SupabaseClientOptionsWithoutAuth } from '@supabase/auth-helpers-shared'; -import { createClient, SupabaseClient } from '@supabase/supabase-js'; +import { SupabaseClient } from '@supabase/supabase-js'; /** * ## Authenticated Supabase client @@ -98,7 +99,7 @@ export function createBrowserClient< cookieOptions }: { options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; } = {} ): SupabaseClient { if (!supabaseUrl || !supabaseKey) { @@ -107,7 +108,7 @@ export function createBrowserClient< ); } - return createClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, @@ -117,19 +118,8 @@ export function createBrowserClient< } }, auth: { - flowType: 'pkce', - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new BrowserCookieAuthStorageAdapter({ - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }) + storageKey: cookieOptions?.name, + storage: new BrowserCookieAuthStorageAdapter(cookieOptions) } }); } @@ -138,9 +128,9 @@ class RemixServerAuthStorageAdapter extends CookieAuthStorageAdapter { constructor( private readonly request: Request, private readonly response: Response, - private readonly cookieOptions?: CookieOptions + cookieOptions?: CookieOptions ) { - super(); + super(cookieOptions); } protected getCookie(name: string): string | null | undefined { @@ -152,7 +142,7 @@ class RemixServerAuthStorageAdapter extends CookieAuthStorageAdapter { // Allow supabase-js on the client to read the cookie as well httpOnly: false }); - this.response.headers.set('set-cookie', cookieStr); + this.response.headers.append('set-cookie', cookieStr); } protected deleteCookie(name: string): void { const cookieStr = serializeCookie(name, '', { @@ -161,7 +151,7 @@ class RemixServerAuthStorageAdapter extends CookieAuthStorageAdapter { // Allow supabase-js on the client to read the cookie as well httpOnly: false }); - this.response.headers.set('set-cookie', cookieStr); + this.response.headers.append('set-cookie', cookieStr); } } @@ -182,7 +172,7 @@ export function createServerClient< request: Request; response: Response; options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; } ): SupabaseClient { if (!supabaseUrl || !supabaseKey) { @@ -197,7 +187,7 @@ export function createServerClient< ); } - return createClient(supabaseUrl, supabaseKey, { + return createSupabaseClient(supabaseUrl, supabaseKey, { ...options, global: { ...options?.global, @@ -207,19 +197,12 @@ export function createServerClient< } }, auth: { - flowType: 'pkce', - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new RemixServerAuthStorageAdapter(request, response, { - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }) + storageKey: cookieOptions?.name, + storage: new RemixServerAuthStorageAdapter( + request, + response, + cookieOptions + ) } }); } diff --git a/packages/shared/src/browserCookieStorage.ts b/packages/shared/src/browserCookieStorage.ts index cdae77f0..2c9c8276 100644 --- a/packages/shared/src/browserCookieStorage.ts +++ b/packages/shared/src/browserCookieStorage.ts @@ -1,11 +1,11 @@ import { parse, serialize } from 'cookie'; import { CookieAuthStorageAdapter } from './cookieAuthStorageAdapter'; import { CookieOptions } from './types'; -import { DEFAULT_COOKIE_OPTIONS, isBrowser } from './utils'; +import { isBrowser } from './utils'; export class BrowserCookieAuthStorageAdapter extends CookieAuthStorageAdapter { - constructor(private readonly cookieOptions?: CookieOptions) { - super(); + constructor(cookieOptions?: CookieOptions) { + super(cookieOptions); } protected getCookie(name: string) { @@ -19,7 +19,6 @@ export class BrowserCookieAuthStorageAdapter extends CookieAuthStorageAdapter { if (!isBrowser()) return null; document.cookie = serialize(name, value, { - ...DEFAULT_COOKIE_OPTIONS, ...this.cookieOptions, httpOnly: false }); @@ -29,7 +28,6 @@ export class BrowserCookieAuthStorageAdapter extends CookieAuthStorageAdapter { if (!isBrowser()) return null; document.cookie = serialize(name, '', { - ...DEFAULT_COOKIE_OPTIONS, ...this.cookieOptions, maxAge: 0, httpOnly: false diff --git a/packages/shared/src/cookieAuthStorageAdapter.ts b/packages/shared/src/cookieAuthStorageAdapter.ts index cb9b71b6..6bc469a3 100644 --- a/packages/shared/src/cookieAuthStorageAdapter.ts +++ b/packages/shared/src/cookieAuthStorageAdapter.ts @@ -1,10 +1,24 @@ import { GoTrueClientOptions, Session } from '@supabase/supabase-js'; -import { parseSupabaseCookie, stringifySupabaseSession } from './utils'; +import { + DEFAULT_COOKIE_OPTIONS, + parseSupabaseCookie, + stringifySupabaseSession +} from './utils'; +import { CookieOptions } from './types'; export interface StorageAdapter extends Exclude {} export abstract class CookieAuthStorageAdapter implements StorageAdapter { + protected readonly cookieOptions: CookieOptions; + + constructor(cookieOptions?: CookieOptions) { + this.cookieOptions = { + ...DEFAULT_COOKIE_OPTIONS, + ...cookieOptions + }; + } + protected abstract getCookie(name: string): string | undefined | null; protected abstract setCookie(name: string, value: string): void; protected abstract deleteCookie(name: string): void; diff --git a/packages/shared/src/createClient.ts b/packages/shared/src/createClient.ts new file mode 100644 index 00000000..337bb17f --- /dev/null +++ b/packages/shared/src/createClient.ts @@ -0,0 +1,34 @@ +import { createClient } from '@supabase/supabase-js'; +import { AuthHelperSupabaseClientOptions } from './types'; +import { isBrowser } from './utils'; + +export function createSupabaseClient< + Database = any, + SchemaName extends string & keyof Database = 'public' extends keyof Database + ? 'public' + : string & keyof Database +>( + supabaseUrl: string, + supabaseKey: string, + options: AuthHelperSupabaseClientOptions +) { + const bowser = isBrowser(); + + return createClient(supabaseUrl, supabaseKey, { + ...options, + auth: { + flowType: 'pkce', + autoRefreshToken: bowser, + detectSessionInUrl: bowser, + persistSession: true, + storage: options.auth.storage, + + // fix this in supabase-js + ...(options.auth?.storageKey + ? { + storageKey: options.auth.storageKey + } + : {}) + } + }); +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 8e76d41d..2c1b1796 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,5 +1,6 @@ export * from './browserCookieStorage'; export * from './cookieAuthStorageAdapter'; +export * from './createClient'; export * from './types'; export { diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts index f1c8329f..81720abc 100644 --- a/packages/shared/src/types.ts +++ b/packages/shared/src/types.ts @@ -1,12 +1,23 @@ import type { CookieSerializeOptions } from 'cookie'; import type { SupabaseClientOptions } from '@supabase/supabase-js'; +import { StorageAdapter } from './cookieAuthStorageAdapter'; -export type CookieOptions = { name?: string } & Pick< +export type CookieOptions = Pick< CookieSerializeOptions, 'domain' | 'secure' | 'path' | 'sameSite' | 'maxAge' >; -export type SupabaseClientOptionsWithoutAuth = Omit< - SupabaseClientOptions, +export type CookieOptionsWithName = { name?: string } & CookieOptions; + +export type SupabaseClientOptionsWithoutAuth = Omit< + SupabaseClientOptions, 'auth' >; + +export type AuthHelperSupabaseClientOptions = + SupabaseClientOptionsWithoutAuth & { + auth: { + storage: StorageAdapter; + storageKey?: string; + }; + }; diff --git a/packages/sveltekit/src/serverStorageAdapter.ts b/packages/sveltekit/src/serverStorageAdapter.ts index 2b3494a7..a21ec455 100644 --- a/packages/sveltekit/src/serverStorageAdapter.ts +++ b/packages/sveltekit/src/serverStorageAdapter.ts @@ -11,10 +11,10 @@ export class SvelteKitServerAuthStorageAdapter extends CookieAuthStorageAdapter constructor( private readonly event: Pick, - private readonly cookieOptions?: CookieOptions, + cookieOptions?: CookieOptions, private readonly expiryMargin: number = 60 ) { - super(); + super(cookieOptions); } protected getCookie(name: string) { diff --git a/packages/sveltekit/src/supabaseLoadClient.ts b/packages/sveltekit/src/supabaseLoadClient.ts index e8fd7f85..29cffa6d 100644 --- a/packages/sveltekit/src/supabaseLoadClient.ts +++ b/packages/sveltekit/src/supabaseLoadClient.ts @@ -1,10 +1,10 @@ import { - CookieOptions, - DEFAULT_COOKIE_OPTIONS, + CookieOptionsWithName, + createSupabaseClient, isBrowser, SupabaseClientOptionsWithoutAuth } from '@supabase/auth-helpers-shared'; -import { createClient, Session, SupabaseClient } from '@supabase/supabase-js'; +import { Session, SupabaseClient } from '@supabase/supabase-js'; import { LoadEvent } from '@sveltejs/kit'; import { SvelteKitLoadAuthStorageAdapter } from './loadStorageAdapter'; @@ -72,42 +72,35 @@ export function createSupabaseLoadClient< */ serverSession: Session | null; options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; }): SupabaseClient { const browser = isBrowser(); if (browser && cachedBrowserClient) { return cachedBrowserClient as SupabaseClient; } - const client = createClient(supabaseUrl, supabaseKey, { - ...options, - global: { - fetch: event.fetch, - ...options?.global, - headers: { - ...options?.global?.headers, - 'X-Client-Info': `${PACKAGE_NAME}@${PACKAGE_VERSION}` + const client = createSupabaseClient( + supabaseUrl, + supabaseKey, + { + ...options, + global: { + fetch: event.fetch, + ...options?.global, + headers: { + ...options?.global?.headers, + 'X-Client-Info': `${PACKAGE_NAME}@${PACKAGE_VERSION}` + } + }, + auth: { + storageKey: cookieOptions?.name, + storage: new SvelteKitLoadAuthStorageAdapter( + serverSession, + cookieOptions + ) } - }, - auth: { - flowType: 'pkce', - autoRefreshToken: browser, - detectSessionInUrl: browser, - persistSession: true, - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new SvelteKitLoadAuthStorageAdapter(serverSession, { - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }) } - }); + ); if (browser) { cachedBrowserClient = client; diff --git a/packages/sveltekit/src/supabaseServerClient.ts b/packages/sveltekit/src/supabaseServerClient.ts index 544b9664..a667a8ea 100644 --- a/packages/sveltekit/src/supabaseServerClient.ts +++ b/packages/sveltekit/src/supabaseServerClient.ts @@ -1,9 +1,8 @@ import { - CookieOptions, - DEFAULT_COOKIE_OPTIONS, - SupabaseClientOptionsWithoutAuth + CookieOptionsWithName, + SupabaseClientOptionsWithoutAuth, + createSupabaseClient } from '@supabase/auth-helpers-shared'; -import { createClient } from '@supabase/supabase-js'; import { RequestEvent } from '@sveltejs/kit'; import { SvelteKitServerAuthStorageAdapter } from './serverStorageAdapter'; @@ -75,41 +74,31 @@ export function createSupabaseServerClient< supabaseKey: string; event: Pick; options?: SupabaseClientOptionsWithoutAuth; - cookieOptions?: CookieOptions; + cookieOptions?: CookieOptionsWithName; expiryMargin?: number; }) { - const client = createClient(supabaseUrl, supabaseKey, { - ...options, - global: { - ...options?.global, - headers: { - ...options?.global?.headers, - 'X-Client-Info': `${PACKAGE_NAME}@${PACKAGE_VERSION}` + const client = createSupabaseClient( + supabaseUrl, + supabaseKey, + { + ...options, + global: { + ...options?.global, + headers: { + ...options?.global?.headers, + 'X-Client-Info': `${PACKAGE_NAME}@${PACKAGE_VERSION}` + } + }, + auth: { + storageKey: cookieOptions?.name, + storage: new SvelteKitServerAuthStorageAdapter( + event, + cookieOptions, + expiryMargin + ) } - }, - auth: { - flowType: 'pkce', - autoRefreshToken: false, - detectSessionInUrl: false, - persistSession: true, - - // fix this in supabase-js - ...(cookieOptions?.name - ? { - storageKey: cookieOptions.name - } - : {}), - - storage: new SvelteKitServerAuthStorageAdapter( - event, - { - ...DEFAULT_COOKIE_OPTIONS, - ...cookieOptions - }, - expiryMargin - ) } - }); + ); return client; }