/supabase-nextjs-middleware

An example of Supabase Auth working with Next.js middleware

Primary LanguageTypeScript

Next.js Middleware and Supabase

(read the blog post about this example)

This app demonstrates how new Next.js 12 middleware works along supabase auth. pages/index.tsx is responsible for login logout using supabase-js lib (client side). Once user logged in, it calls pages/api/set.ts to set a server-side cookie containing supabase JWT token. After logout, pages/api/remove.ts is called to clear JWT cookie

Every page inside pages/app/ is filtered by pages/app/_middleware.ts (see how Next.js middleware works). Middleware validates supabase JWT token (by calling supabase HTTP API). If the token is absent (=cookie has not been set) or is invalid (auth expired etc), user will be redirected to login page. Thus, all pages in the /app is accessible only by authorised users

Deployment and running

The app requires NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_KEY environment variables to be set. Read more on Supabase Docs site.

Run the app with yarn install && NEXT_PUBLIC_SUPABASE_URL="..." NEXT_PUBLIC_SUPABASE_KEY="..." next start. Open localhost:3000 to access it

Getting user server-side

See pages/app/hidden-page.tsx. In there, supabase user is obtained during server-side rendering. Since pages/app/_middleware.ts has already validated the user. We don't need to verify JWT with supabase server call, we can just decode JWT

Having user on getServerSideProps we pre-build some data on server (e.g. query user settings from DB). And we will save an extra request to subapase server client-side


The bug

This project also reproduces the bug with supabase-js lib. See _middleware.js. In theory, if you uncomment supabase.auth.api.getUserByCookie and comment getUser the app should remain functinal. However, here's what happens:

Authorization error, redirecting to login page ReferenceError: XMLHttpRequest is not defined
    at eval (webpack-internal:///./node_modules/cross-fetch/dist/browser-ponyfill.js?d2fb:462:17)
    at new Promise (<anonymous>)
    at fetch (webpack-internal:///./node_modules/cross-fetch/dist/browser-ponyfill.js?d2fb:455:12)
    at eval (webpack-internal:///./node_modules/@supabase/gotrue-js/dist/module/lib/fetch.js?85f4:44:63)
    at new Promise (<anonymous>)
    at eval (webpack-internal:///./node_modules/@supabase/gotrue-js/dist/module/lib/fetch.js?85f4:43:16)
    at Generator.next (<anonymous>)
    at eval (webpack-internal:///./node_modules/@supabase/gotrue-js/dist/module/lib/fetch.js?85f4:16:71)
    at new Promise (<anonymous>)
    at __awaiter (webpack-internal:///./node_modules/@supabase/gotrue-js/dist/module/lib/fetch.js?85f4:12:12)