supabase / auth-helpers

A collection of framework specific Auth utilities for working with Supabase.
https://supabase.github.io/auth-helpers/
MIT License
908 stars 232 forks source link

Cookie is too large #643

Open mbalslow opened 1 year ago

mbalslow commented 1 year ago

Bug report

Describe the bug

I have a SvelteKit app that uses the latest await supabase.auth.exchangeCodeForSession(code); auth logic with Azure as the provider and everything works fine. However, if I attempt to expand my "scopes" with offline_access to get the provider_refresh_token, I get the following error:

Error: Cookie "sb-xxxxxxxxxxxxx-auth-token" is too large, and will be discarded by the browser
    at set_internal (C:/Users/mbalslow/GitHub/basico-mit-website/node_modules/@sveltejs/kit/src/runtime/server/cookie.js:195:11)
    at Object.set (C:/Users/mbalslow/GitHub/basico-mit-website/node_modules/@sveltejs/kit/src/runtime/server/cookie.js:114:4)
    at SvelteKitServerAuthStorageAdapter.setCookie (file:///C:/Users/mbalslow/GitHub/basico-mit-website/node_modules/@supabase/auth-helpers-sveltekit/dist/index.js:80:24)
    at SvelteKitServerAuthStorageAdapter.setItem (C:\Users\mbalslow\GitHub\basico-mit-website\node_modules\@supabase\auth-helpers-shared\dist\index.js:276:10)
    at setItemAsync (C:\Users\mbalslow\GitHub\basico-mit-website\node_modules\@supabase\gotrue-js\dist\main\lib\helpers.js:129:19)
    at SupabaseAuthClient._persistSession (C:\Users\mbalslow\GitHub\basico-mit-website\node_modules\@supabase\gotrue-js\dist\main\GoTrueClient.js:1328:43)
    at SupabaseAuthClient._saveSession (C:\Users\mbalslow\GitHub\basico-mit-website\node_modules\@supabase\gotrue-js\dist\main\GoTrueClient.js:1323:24)
    at SupabaseAuthClient._exchangeCodeForSession (C:\Users\mbalslow\GitHub\basico-mit-website\node_modules\@supabase\gotrue-js\dist\main\GoTrueClient.js:353:24)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async C:\Users\mbalslow\GitHub\basico-mit-website\node_modules\@supabase\gotrue-js\dist\main\GoTrueClient.js:643:28

As soon as I remove offline_access, it works. It seems that too much data in put into the same cookie.

Expected behavior

Maybe an option to have the provider details in a separate cookie or somehow be able to control how the session is stored in one or more cookies. The current implementation makes it impossible to get a hold of the provider_refresh_token, which is critical for our implementation.

silentworks commented 1 year ago

This is a known issue with cookies that they have a size limit. You can create your own cookie storage driver for the auth-helpers and handle cookie chunking in it. We had something we were working on to handle the chunking but we had issues in Safari.

mbalslow commented 1 year ago

Can you point me in some direction on how to do this @silentworks?

silentworks commented 1 year ago

@mbalslow I have a working branch at the moment that will get merged in within the next few days to resolve this issue. Here is the PR https://github.com/supabase/auth-helpers/pull/653

tobiassern commented 1 year ago

@silentworks I see that this has now been merged, thank you for fixing it. But how do I use it, my current code is the same as is the same as in the tutorial -> https://supabase.com/docs/guides/auth/server-side/creating-a-client?framework=sveltekit

What do i need to change, update in order to get this to work?

silentworks commented 1 year ago

@tobiassern the update you saw here was related to @supabase/auth-helpers and not @supabase/ssr. However we have now shipped this feature in the @supabase/ssr package too. But for SvelteKit there is a caveat in the createBrowser where you need to setup the cookies.get to handle chunking. I will add this to the guides soon.

tobiassern commented 1 year ago

@silentworks thank you for the update, looking forward to the updated guides.

silentworks commented 1 year ago

@tobiassern updated guides are now published.

mattiasbonte commented 1 year ago

Hello guys, I've implemented the chunking as described in the new documentation and updated my package to 0.0.8. But it seems now the logout action doesn't actually log out the user anymore. Does someone else encounter the same issue or is this something on my end?

I believe this issue is related/possibly the same. Since I now have 2 cookies with undefined living in my cookie storage at all times. Even when logged out.

silentworks commented 1 year ago

@mattiasbonte there was a bug in 0.0.8, we've since reverted the change that caused the bug and released 0.0.9. Please test out 0.0.9 and let us know if the issue has been resolved.

mattiasbonte commented 1 year ago

Hey @silentworks, I've downloaded the update and did a full test and now I see the undefined cookies are indeed gone and renamed to sb-oqwjnxpmowajlgwaoqcs-auth-token.0 and sb-oqwjnxpmowajlgwaoqcs-auth-token.1.

But the logout functionality is still broken. The thing is, when the supabase.auth.signOut() function is executed the cookie storage is still populated with the 2 cookies mentioned above. I assume this is the reason the logout fails?

silentworks commented 1 year ago

@mattiasbonte you will need to create a reproducible example of this as I've tested this on my side and cannot replicate this issue.

mattiasbonte commented 1 year ago

You can have this code in the src/routes/layout.ts file to reproduce.

    /**
     * Supabase Client Side (Browser) Client.
     * @info The server side client lives in `hooks.server.ts`
     */
    const supabase = createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
        global: {
            fetch,
        },
        cookies: {
            get(key) {
                if (!isBrowser()) {
                    return JSON.stringify(data.session);
                }
                const cookie = combineChunks(key, (name) => {
                    const cookies = parse(document.cookie);
                    return cookies[name];
                });
                return cookie;
            },
        },
    });

    // should directly sign the user out after instantiation?
    await supabase.auth.signOut();
       // but nothing happens.

@silentworks So when I use the supabase server client to execute the auth.signOut action, everything works as expected. It's when I use the browser client that it fails to work. I've tried to call my browser client in different parts of the app but all with the same result.

Does the signout action works on both your browserClient and serverClient? If yes, I will have to dig deeper.

silentworks commented 1 year ago

@mattiasbonte That is not how you would write a signout with the library. Please provide a reproducible Github repo, the snippets you are providing doesn't make much sense to someone else who doesn't have context of your project. Also you should probably create a new issue as this is no longer related to this original issue here.

dvvolynkin commented 1 year ago

@silentworks

export const createSupabaseRouteHandlerClient = (anon: boolean = true): SupabaseClient<Database> => {
  const cookieStore = cookies()

  return sbSSR.createServerClient<Database>(
    env.NEXT_PUBLIC_SUPABASE_URL!,
    anon ? env.NEXT_PUBLIC_SUPABASE_ANON_KEY! : env.SUPABASE_SERVICE_ROLE_KEY!,
    {
      cookieOptions: getCookieOptions(),
      cookies: {
        get(name: string) {
          return cookieStore.get(name)?.value
        },
        set(name: string, value: string, options: sbSSR.CookieOptions) {
          console.log("cookie length", value.length)
          cookieStore.set({ name, value, ...options })
        },
        remove(name: string, options: sbSSR.CookieOptions) {
          cookieStore.set({ name, value: '', ...options })
        },
      },
    }
  )
}

cookie length in chunk is 3143

But after encoding in Set-Cookie header value length is 4262

silentworks commented 1 year ago

@dvvolynkin it would be useful to see the content your getCookieOptions() function returns.

dvvolynkin commented 1 year ago
export const getCookieOptions = (): sbSSR.CookieOptions => {
  const hostname = new URL(env.NEXT_PUBLIC_APP_URL).hostname;
  const isHostSecure = env.NEXT_PUBLIC_APP_URL.startsWith('https://');
  const twelveMonths = 60 * 60 * 24 * 30 * 12;
  return {
    domain: hostname,
    path: '/',
    secure: isHostSecure,
    sameSite: 'none',
    maxAge: twelveMonths
  };
};
sharkstate commented 1 year ago

@tobiassern the update you saw here was related to @supabase/auth-helpers and not @supabase/ssr. However we have now shipped this feature in the @supabase/ssr package too. But for SvelteKit there is a caveat in the createBrowser where you need to setup the cookies.get to handle chunking. I will add this to the guides soon.

Ive made the changes posted in the guide here:

https://supabase.com/docs/guides/auth/server-side/creating-a-client?framework=sveltekit&environment=layout

eg added:

import { combineChunks, createBrowserClient, isBrowser, parse } from '@supabase/ssr'

however, get:

The requested module '...@supabase_ssr.js?v=3acaaab5' does not provide an export named 'combineChunks'

sharkstate commented 1 year ago

@tobiassern the update you saw here was related to @supabase/auth-helpers and not @supabase/ssr. However we have now shipped this feature in the @supabase/ssr package too. But for SvelteKit there is a caveat in the createBrowser where you need to setup the cookies.get to handle chunking. I will add this to the guides soon.

Ive made the changes posted in the guide here:

https://supabase.com/docs/guides/auth/server-side/creating-a-client?framework=sveltekit&environment=layout

eg added:

import { combineChunks, createBrowserClient, isBrowser, parse } from '@supabase/ssr'

however, get:

The requested module '...@supabase_ssr.js?v=3acaaab5' does not provide an export named 'combineChunks'

Sorry. Got it, 0.0.9

DiegusAurelius commented 10 months ago

@tobiassern updated guides are now published.

Im having the same exact issue. IM using the SSR package 0.0.10, and Sveltekit 2.0.0. While authenticating with Facebook and Magic Link I get a 500 Internal error and "Cookie "sb-**-auth-token.1" is too large, and will be discarded by the browser. I tried the combineChunk method, but didn't work.

badgifter commented 10 months ago

Got same issue as well. For us, we were setting avatar_local="server.com/v1/storage/etc/etc/uuid/img_name_is_really_long_for_some_random_reason_prob_ai_gen_image.webp?width=200

I noticed when a person uploads a large name image for their avatar, once we set the avatar_url in their user_info, login no longer worked. I think the chunks being made didn't account for large key:value items in the raw user metadata?

Temp solution until chunking is improved. Avoid large key:value in the user data you save, and avoid saving lots of user data.

Raidus commented 10 months ago

Same issue here. Any update on the issue?

dantrain commented 10 months ago

Until the chunking is fixed I found a way around this by gzipping the chunk values like this in the setter:

zlib.gzipSync(Buffer.from(value, "utf-8")).toString("base64url")

and in the getter the reverse:

zlib.gunzipSync(Buffer.from(value, "base64url")).toString("utf-8")

This seems to make them short enough to work for me, YMMV.

thibistaken commented 9 months ago

Same issue trying the PKCE email and oauth flows with Supabase SSR. Any update? Thanks!

charislam commented 9 months ago

@thibistaken which version of @supabase/ssr are you on? There was a fix in 0.1.0 related to this

thibistaken commented 9 months ago

I just upgraded from 0.0.5 to 0.1.0 and it seems it is working now? Will test it out a bit more. Thanks @charislam!

mb21 commented 8 months ago

Am I right in assuming that we need the chunking only because we store so much stuff in the cookies, much of it redundant information? Wouldn't it be enough to store only the access token and refresh token? All the other info can be derived from that server-side?

yulluone commented 7 months ago

@tobiassern the update you saw here was related to @supabase/auth-helpers and not @supabase/ssr. However we have now shipped this feature in the @supabase/ssr package too. But for SvelteKit there is a caveat in the createBrowser where you need to setup the cookies.get to handle chunking. I will add this to the guides soon.

Thank you for this,

I had been struggling with Google OAuth not working for hours, once I narrowed it down to a cookie-setting issue (the cookie was too large)... I came across this issue... A @supabase/ssr update from 0.0.5 to 0.3.0 fixed the issue.

contactjavas commented 6 months ago

Currently, this issue still exists even with latest supabase-js and supabase-ssr. The effective solution for now is to minimalize the data in user_metadata field.

gludington commented 5 months ago

Following up mb21's earlier comment, is there an ability to configure/whitelist claims that go to the client (and therefore the cookie) to a minimal set, so that it is present in postgres for use, but not emitted to the client? Size aside, some of the information in that cookie might test the boundaries of what GDPR would consider "strictly necessary."

teamclouday commented 5 months ago

I have a socketio setup that connects to a python server which uses websockets. Apparently there's a hard limit of cookie size in header (8k) and my client keeps getting disconnected because of the large auth tokens created by supabase auth. Really hope there's a way to reduce the size.

yekta commented 3 months ago

We are having the same issue with supabase/ssr. This not only breaks Nginx default config but also breaks Cloudflare. Some users have 2 chunks, some have 4. Even 2 chunks is dangerously close to standard header size limit when combined with other mid-sized cookies.

oldbettie commented 2 months ago

This seems to be a consistent issue. Why don't you store just the access_token, refresh_token in the original cookie and any other stuff can just do in cookie-name.1???? that seems pretty logical and simple it would not break everytime it chunks the cookie

danperks commented 1 month ago

I'm using Nuxt, and I've just gone through and updated all my project dependencies to the latest version. Interestingly, I wasn't having this issue before, but seemingly at random, I'm getting "Bad Request" errors stating my request header field exceeds server limit from NGINX.

Seems to match @yekta's issue, and this is all on the latest versions of packages.

EDIT: This is now a pretty critical issue for me, as it seems both Cloudflare and my NGINX reverse proxy are trashing requests with a cookie that is too long.

serhii-kucherenko commented 1 month ago

Same issue here. Nextjs just stops processing requests. Any updates on how to fix it?

oof2win2 commented 1 week ago

Same happens to me here. Vercel middleware is fully discarding all requests - there's too much data across all cookies combined and Vercel just discards the request