Open hf opened 7 months ago
pnpm build:nextjs
fails - also, ifcreateMiddlewareClient
is broken, why not just modify the implementation to callcreateMiddlewareClient2
under the hood instead?
As described in the PR -- to forward the headers NextResponse.next()
should be called after the client has processed the session.
@hf you need to export the new client in the index.ts
file too
@hf the return types don't show up correctly when the client is instantiated, which isn't great DX-wise
const [supabaseClient, nextResponse] = createMiddlewareClient2(req);
it seems to think that createMiddlewareClient2
returns (SupabaseClient<any, "public", any> | (() => NextResponse<...>))[]
(note the |
)
createMiddlewareClient
was basically completely broken for correctly syncing the session state between the server and browser parts of a NextJS application.It works in most situations where the user is actively interacting with the site, but as soon as they leave the site for an extended period of time and come back, it's very likely that after the JWT expiry time they will receive an Invalid Refresh Token error from the server. Because these events are not time-correlated, it's impossible to debug what is causing them.
Why does this happen:
NextResponse.next()
is not enough. Pages, server-rendered components and route handlers do not see theSet-Cookie
header set on the response.middleware.ts
file, the session is correctly refreshed in the middleware client and theSet-Cookie
headers are set on the response so the browser syncs up with the state of the middleware client.cookie
header from the request which is the old session and any use ofgetSession()
orgetUser()
will refresh the session every time. If you have, say, 3 Data API calls to PostgREST, it's very likely that the session would be refreshed 3 times.middleware.ts
) and be greeted with the "Invalid Refresh Token" error.How is this being fixed:
The design of
createMiddlewareClient
does not care at all about what happens to the request, but this is incredibly important so the new refreshed session is passed down to the page or server-rendered component. Furthermore, this cannot "just be set" as for the propagation to take place,NextResponse.next({ request })
needs to be called.Therefore,
createMiddlewareClient
is fully deprecated and replaced with its new counterpartcreateMiddlewareClient2
. This works a bit differently (without reinventing the simplistic beauty of the@supabase/ssr
package):Firstly it returns two arguments, the Supabase client and a
nextResponse
function. It should be called towards the bottom of themiddleware.ts
file, ideally in thereturn
statement.The client is setup such that, it initially reads from the request's
Cookie
header, but writes the changes to local memory. It tracks what items (not cookies!) are being set or deleted.When you call
nextResponse()
the requests'sCookie
header is reset to reflect the new state of the Supabase client. Because this header will just be propagated down to the page or server-rendered component, no cookie chunking is necessary.Then, it calls:
Which ensures that the request's changes will be actually propagated down to the page or component. This enables the clients there to pick up the
Cookie
header which now includes the refreshed session.Finally, it sets the
Set-Cookie
header on the response, which eventually reaches the browser and the session state is finally synchronized between them.