supabase / ssr

Supabase clients for use in server-side rendering frameworks.
MIT License
56 stars 6 forks source link

AuthApiError: Invalid Refresh Token: Refresh Token Not Found when refreshing token in middleware #68

Open lourd opened 2 hours ago

lourd commented 2 hours ago

Bug report

Describe the bug

I'm inadvertently logged out of my web application every day, with this error in the back-end logs: AuthApiError: Invalid Refresh Token: Refresh Token Not Found.

I recently set up Supabase auth on my new Next.js application. I followed the Setting up Server-Side Auth for Next.js guide, with some small tweaks. My code looks like this:

middleware.ts ```ts import { type NextRequest } from "next/server" import { updateSession } from "./app/supabase/middleware" export async function middleware(request: NextRequest) { return await updateSession(request) } export const config = { matcher: [ /* * Match all request paths except for the ones starting with: * - _next/static (static files) * - _next/image (image optimization files) * - favicon.ico (favicon file) * - @vercel/speed-insights script */ "/((?!_next/static|_next/image|favicon.ico|_vercel/speed-insights|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", ], } ```
app/supabase/middleware.ts ```ts import { CookieMethodsServer, createServerClient } from "@supabase/ssr" import { NextResponse, type NextRequest } from "next/server" export async function updateSession(request: NextRequest) { const response = NextResponse.next({ request }) const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: nextMiddlewareCookies(request, response), } ) await supabase.auth.getSession() return response } function nextMiddlewareCookies( req: NextRequest, res: NextResponse ): CookieMethodsServer { return { getAll() { return req.cookies.getAll() }, setAll(cookiesToSet) { cookiesToSet.forEach((cookie) => { req.cookies.set(cookie.name, cookie.value) res.cookies.set(cookie.name, cookie.value, cookie.options) }) }, } } ```

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Use the snippets above to set up token refresh with middleware
  2. Log in
  3. Wait 24 hours
  4. Load any page that will hit the middleware, which for me is any page of my application.
  5. Get the AuthApiError: Invalid Refresh Token: Refresh Token Not Found error in your middleware logs

Expected behavior

The token should refresh if there is one and it's expired, without an error. If there's not a session, it should not try to refresh it, and there should be no error.

Screenshots

From my Vercel logs:

Screenshot 2024-09-22 at 12 24 16 PM

System information

Additional context

This appears to be the same or a similar bug as https://github.com/supabase/auth-helpers/issues/436.

I've tried forcing the issue to happen more quickly by shortening the JWT expiry to 60 seconds, but it refreshes just fine. There's something with the 24 hour window that seems to be causing the error.

lourd commented 2 hours ago

I'll point out that I didn't copy the guide code 100% because it doesn't seem necessary to loop through the cookiesToSet twice and make a new response each time, seems inefficient to me. These lines:

https://github.com/supabase/supabase/blob/9e0e4f652b772d37cf5da1388f0fd3d71ed3dd39/apps/docs/content/guides/auth/server-side/nextjs.mdx?plain=1#L237-L244

Please correct me if I'm wrong!

lourd commented 1 hour ago

Also, you don't need to set the updated cookies on the request and the response in the middleware. Setting them on the response makes them available to the downstream server components reading from cookies() as of this change back in April https://github.com/vercel/next.js/pull/65008