From 59c3a4c6eab1320a0b49dae50bcb385a82444910 Mon Sep 17 00:00:00 2001 From: Alican Erdurmaz Date: Wed, 29 May 2024 10:47:01 +0300 Subject: [PATCH] fix(nextjs): supabase authflow --- .../src/app/blog-posts/show/[id]/page.tsx | 2 +- .../src/app/categories/show/[id]/page.tsx | 2 +- .../plugins/data-provider-supabase/extend.js | 4 +- .../data-provider-supabase/package.json | 1 + .../data-provider-supabase/src/middleware.ts | 20 +++++++ ...th-provider.ts => auth-provider.client.ts} | 41 ++++++------- .../auth-provider/auth-provider.server.ts | 21 +++++-- .../src/providers/auth-provider/index.ts | 4 +- .../src/providers/data-provider/index.ts | 4 +- .../src/utility/supabase-client.ts | 14 ----- .../src/utils/supabase/client.ts | 12 ++++ .../src/utils/supabase/constants.ts | 3 + .../src/utils/supabase/middleware.ts | 57 +++++++++++++++++++ .../src/utils/supabase/server.ts | 33 +++++++++++ .../src/app/blog-posts/show/[id]/page.tsx | 2 +- .../src/app/categories/show/[id]/page.tsx | 2 +- .../routes/_layout.blog-posts.show.$id.tsx | 2 +- .../routes/_layout.categories.show.$id.tsx | 2 +- .../routes/_layout.blog-posts.show.$id.tsx | 2 +- .../routes/_layout.categories.show.$id.tsx | 2 +- .../src/pages/blog-posts/show.tsx | 2 +- .../src/pages/categories/show.tsx | 2 +- .../mui-example/src/pages/blog-posts/show.tsx | 2 +- .../mui-example/src/pages/categories/show.tsx | 2 +- 24 files changed, 181 insertions(+), 57 deletions(-) create mode 100644 refine-nextjs/plugins/data-provider-supabase/src/middleware.ts rename refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/{auth-provider.ts => auth-provider.client.ts} (72%) delete mode 100644 refine-nextjs/plugins/data-provider-supabase/src/utility/supabase-client.ts create mode 100644 refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/client.ts create mode 100644 refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/constants.ts create mode 100644 refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/middleware.ts create mode 100644 refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/server.ts diff --git a/refine-nextjs/plugins/antd-example/src/app/blog-posts/show/[id]/page.tsx b/refine-nextjs/plugins/antd-example/src/app/blog-posts/show/[id]/page.tsx index df317ba4..a26fdad8 100644 --- a/refine-nextjs/plugins/antd-example/src/app/blog-posts/show/[id]/page.tsx +++ b/refine-nextjs/plugins/antd-example/src/app/blog-posts/show/[id]/page.tsx @@ -59,7 +59,7 @@ export default function BlogPostShow() { return ( {"ID"} - + {"Title"} {"Content"} diff --git a/refine-nextjs/plugins/antd-example/src/app/categories/show/[id]/page.tsx b/refine-nextjs/plugins/antd-example/src/app/categories/show/[id]/page.tsx index 85a7b4c6..538d57bc 100644 --- a/refine-nextjs/plugins/antd-example/src/app/categories/show/[id]/page.tsx +++ b/refine-nextjs/plugins/antd-example/src/app/categories/show/[id]/page.tsx @@ -34,7 +34,7 @@ export default function CategoryShow() { return ( {"ID"} - + {"Title"} diff --git a/refine-nextjs/plugins/data-provider-supabase/extend.js b/refine-nextjs/plugins/data-provider-supabase/extend.js index 366f2184..e43e3c29 100644 --- a/refine-nextjs/plugins/data-provider-supabase/extend.js +++ b/refine-nextjs/plugins/data-provider-supabase/extend.js @@ -2,11 +2,11 @@ const base = { _app: { import: [], localImport: [ - 'import { authProvider } from "@providers/auth-provider";', + 'import { authProviderClient } from "@providers/auth-provider";', 'import { dataProvider } from "@providers/data-provider";', ], refineProps: [ - "authProvider={authProvider}", + "authProvider={authProviderClient}", "dataProvider={dataProvider}", ], refineAntdImports: [], diff --git a/refine-nextjs/plugins/data-provider-supabase/package.json b/refine-nextjs/plugins/data-provider-supabase/package.json index 45fe38bb..77eaf45a 100644 --- a/refine-nextjs/plugins/data-provider-supabase/package.json +++ b/refine-nextjs/plugins/data-provider-supabase/package.json @@ -1,6 +1,7 @@ { "dependencies": { "@refinedev/supabase": "^5.7.4", + "@supabase/ssr": "^0.3.0", "js-cookie": "^3.0.5" }, "devDependencies": { diff --git a/refine-nextjs/plugins/data-provider-supabase/src/middleware.ts b/refine-nextjs/plugins/data-provider-supabase/src/middleware.ts new file mode 100644 index 00000000..376076d9 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/middleware.ts @@ -0,0 +1,20 @@ +import { updateSession } from "@/utils/supabase/middleware"; +import type { NextRequest } from "next/server"; + +export async function middleware(request: NextRequest) { + const result = await updateSession(request); + return result; +} + +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) + * Feel free to modify this pattern to include more paths. + */ + "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)", + ], +}; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.client.ts similarity index 72% rename from refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.ts rename to refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.client.ts index 8772fb21..e53515ab 100644 --- a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.ts +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.client.ts @@ -1,15 +1,15 @@ "use client"; -import { AuthBindings } from "@refinedev/core"; -import { supabaseClient } from "@utility/supabase-client"; -import Cookies from "js-cookie"; +import type { AuthProvider } from "@refinedev/core"; +import { supabaseBrowserClient } from "@utils/supabase/client"; -export const authProvider: AuthBindings = { +export const authProviderClient: AuthProvider = { login: async ({ email, password }) => { - const { data, error } = await supabaseClient.auth.signInWithPassword({ - email, - password, - }); + const { data, error } = + await supabaseBrowserClient.auth.signInWithPassword({ + email, + password, + }); if (error) { return { @@ -19,10 +19,7 @@ export const authProvider: AuthBindings = { } if (data?.session) { - Cookies.set("token", data.session.access_token, { - expires: 30, // 30 days - path: "/", - }); + await supabaseBrowserClient.auth.setSession(data.session); return { success: true, @@ -40,8 +37,7 @@ export const authProvider: AuthBindings = { }; }, logout: async () => { - Cookies.remove("token", { path: "/" }); - const { error } = await supabaseClient.auth.signOut(); + const { error } = await supabaseBrowserClient.auth.signOut(); if (error) { return { @@ -57,7 +53,7 @@ export const authProvider: AuthBindings = { }, register: async ({ email, password }) => { try { - const { data, error } = await supabaseClient.auth.signUp({ + const { data, error } = await supabaseBrowserClient.auth.signUp({ email, password, }); @@ -91,10 +87,17 @@ export const authProvider: AuthBindings = { }; }, check: async () => { - const token = Cookies.get("token"); - const { data } = await supabaseClient.auth.getUser(token); + const { data, error } = await supabaseBrowserClient.auth.getUser(); const { user } = data; + if (error) { + return { + authenticated: false, + redirectTo: "/login", + logout: true, + }; + } + if (user) { return { authenticated: true, @@ -107,7 +110,7 @@ export const authProvider: AuthBindings = { }; }, getPermissions: async () => { - const user = await supabaseClient.auth.getUser(); + const user = await supabaseBrowserClient.auth.getUser(); if (user) { return user.data.user?.role; @@ -116,7 +119,7 @@ export const authProvider: AuthBindings = { return null; }, getIdentity: async () => { - const { data } = await supabaseClient.auth.getUser(); + const { data } = await supabaseBrowserClient.auth.getUser(); if (data?.user) { return { diff --git a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.server.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.server.ts index ade4d473..612fcaac 100644 --- a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.server.ts +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/auth-provider.server.ts @@ -1,12 +1,21 @@ -import { AuthBindings } from "@refinedev/core"; -import { cookies } from "next/headers"; +import type { AuthProvider } from "@refinedev/core"; +import { createSupabaseServerClient } from "@utils/supabase/server"; -export const authProviderServer: Pick = { +export const authProviderServer: Pick = { check: async () => { - const cookieStore = cookies(); - const auth = cookieStore.get("token"); + const { data, error } = + await createSupabaseServerClient().auth.getUser(); + const { user } = data; - if (auth) { + if (error) { + return { + authenticated: false, + logout: true, + redirectTo: "/login", + }; + } + + if (user) { return { authenticated: true, }; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/index.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/index.ts index b7f6d9fe..eaf5c1c6 100644 --- a/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/index.ts +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/auth-provider/index.ts @@ -1,2 +1,2 @@ -export * from './auth-provider' -export * from './auth-provider.server' +export * from "./auth-provider.client"; +export * from "./auth-provider.server"; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/providers/data-provider/index.ts b/refine-nextjs/plugins/data-provider-supabase/src/providers/data-provider/index.ts index afe23fac..d18fb139 100644 --- a/refine-nextjs/plugins/data-provider-supabase/src/providers/data-provider/index.ts +++ b/refine-nextjs/plugins/data-provider-supabase/src/providers/data-provider/index.ts @@ -1,6 +1,6 @@ "use client"; import { dataProvider as dataProviderSupabase } from "@refinedev/supabase"; -import { supabaseClient } from "@utility/supabase-client"; +import { supabaseBrowserClient } from "@utils/supabase/client"; -export const dataProvider = dataProviderSupabase(supabaseClient); +export const dataProvider = dataProviderSupabase(supabaseBrowserClient); diff --git a/refine-nextjs/plugins/data-provider-supabase/src/utility/supabase-client.ts b/refine-nextjs/plugins/data-provider-supabase/src/utility/supabase-client.ts deleted file mode 100644 index 595273b8..00000000 --- a/refine-nextjs/plugins/data-provider-supabase/src/utility/supabase-client.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createClient } from "@refinedev/supabase"; - -const SUPABASE_URL = "https://iwdfzvfqbtokqetmbmbp.supabase.co"; -const SUPABASE_KEY = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzMDU2NzAxMCwiZXhwIjoxOTQ2MTQzMDEwfQ._gr6kXGkQBi9BM9dx5vKaNKYj_DJN1xlkarprGpM_fU"; - -export const supabaseClient = createClient(SUPABASE_URL, SUPABASE_KEY, { - db: { - schema: "public", - }, - auth: { - persistSession: true, - }, -}); diff --git a/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/client.ts b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/client.ts new file mode 100644 index 00000000..b7aa1741 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/client.ts @@ -0,0 +1,12 @@ +import { createBrowserClient } from "@supabase/ssr"; +import { SUPABASE_KEY, SUPABASE_URL } from "./constants"; + +export const supabaseBrowserClient = createBrowserClient( + SUPABASE_URL, + SUPABASE_KEY, + { + db: { + schema: "public", + }, + }, +); diff --git a/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/constants.ts b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/constants.ts new file mode 100644 index 00000000..84d1dd96 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/constants.ts @@ -0,0 +1,3 @@ +export const SUPABASE_URL = "https://iwdfzvfqbtokqetmbmbp.supabase.co"; +export const SUPABASE_KEY = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzMDU2NzAxMCwiZXhwIjoxOTQ2MTQzMDEwfQ._gr6kXGkQBi9BM9dx5vKaNKYj_DJN1xlkarprGpM_fU"; diff --git a/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/middleware.ts b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/middleware.ts new file mode 100644 index 00000000..0329db12 --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/middleware.ts @@ -0,0 +1,57 @@ +import { CookieOptions, createServerClient } from "@supabase/ssr"; +import { NextRequest, NextResponse } from "next/server"; +import { SUPABASE_KEY, SUPABASE_URL } from "./constants"; + +export async function updateSession(request: NextRequest) { + let response = NextResponse.next({ + request: { + headers: request.headers, + }, + }); + + const supabase = createServerClient(SUPABASE_URL, SUPABASE_KEY, { + cookies: { + get(name: string) { + return request.cookies.get(name)?.value; + }, + set(name: string, value: string, options: CookieOptions) { + request.cookies.set({ + name, + value, + ...options, + }); + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }); + response.cookies.set({ + name, + value, + ...options, + }); + }, + remove(name: string, options: CookieOptions) { + request.cookies.set({ + name, + value: "", + ...options, + }); + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }); + response.cookies.set({ + name, + value: "", + ...options, + }); + }, + }, + }); + + await supabase.auth.getUser(); + + return response; +} diff --git a/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/server.ts b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/server.ts new file mode 100644 index 00000000..8d82907c --- /dev/null +++ b/refine-nextjs/plugins/data-provider-supabase/src/utils/supabase/server.ts @@ -0,0 +1,33 @@ +import { CookieOptions, createServerClient } from "@supabase/ssr"; +import { cookies } from "next/headers"; +import { SUPABASE_KEY, SUPABASE_URL } from "./constants"; + +export const createSupabaseServerClient = () => { + const cookieStore = cookies(); + + return createServerClient(SUPABASE_URL, SUPABASE_KEY, { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value; + }, + set(name: string, value: string, options: CookieOptions) { + try { + cookieStore.set({ name, value, ...options }); + } catch (error) { + // The `set` method was called from a Server Component. + // This can be ignored if you have middleware refreshing + // user sessions. + } + }, + remove(name: string, options: CookieOptions) { + try { + cookieStore.set({ name, value: "", ...options }); + } catch (error) { + // The `delete` method was called from a Server Component. + // This can be ignored if you have middleware refreshing + // user sessions. + } + }, + }, + }); +}; diff --git a/refine-nextjs/plugins/mui-example/src/app/blog-posts/show/[id]/page.tsx b/refine-nextjs/plugins/mui-example/src/app/blog-posts/show/[id]/page.tsx index df081ba7..f0d9c468 100644 --- a/refine-nextjs/plugins/mui-example/src/app/blog-posts/show/[id]/page.tsx +++ b/refine-nextjs/plugins/mui-example/src/app/blog-posts/show/[id]/page.tsx @@ -62,7 +62,7 @@ export default function BlogPostShow() { {"ID"} - + {"Title"} diff --git a/refine-nextjs/plugins/mui-example/src/app/categories/show/[id]/page.tsx b/refine-nextjs/plugins/mui-example/src/app/categories/show/[id]/page.tsx index b76278cd..472803c1 100644 --- a/refine-nextjs/plugins/mui-example/src/app/categories/show/[id]/page.tsx +++ b/refine-nextjs/plugins/mui-example/src/app/categories/show/[id]/page.tsx @@ -37,7 +37,7 @@ export default function CategoryShow() { {"ID"} - + {"Title"} diff --git a/refine-remix/plugins/antd-example/app/routes/_layout.blog-posts.show.$id.tsx b/refine-remix/plugins/antd-example/app/routes/_layout.blog-posts.show.$id.tsx index f6d5bbb5..c51020ae 100644 --- a/refine-remix/plugins/antd-example/app/routes/_layout.blog-posts.show.$id.tsx +++ b/refine-remix/plugins/antd-example/app/routes/_layout.blog-posts.show.$id.tsx @@ -57,7 +57,7 @@ export default function BlogPostShow() { return ( {"ID"} - + {"Title"} {"Content"} diff --git a/refine-remix/plugins/antd-example/app/routes/_layout.categories.show.$id.tsx b/refine-remix/plugins/antd-example/app/routes/_layout.categories.show.$id.tsx index d5679cee..7abddffd 100644 --- a/refine-remix/plugins/antd-example/app/routes/_layout.categories.show.$id.tsx +++ b/refine-remix/plugins/antd-example/app/routes/_layout.categories.show.$id.tsx @@ -31,7 +31,7 @@ export default function CategoryShow() { return ( {"ID"} - + {"Title"} diff --git a/refine-remix/plugins/mui-example/app/routes/_layout.blog-posts.show.$id.tsx b/refine-remix/plugins/mui-example/app/routes/_layout.blog-posts.show.$id.tsx index 4036862c..196c6de0 100644 --- a/refine-remix/plugins/mui-example/app/routes/_layout.blog-posts.show.$id.tsx +++ b/refine-remix/plugins/mui-example/app/routes/_layout.blog-posts.show.$id.tsx @@ -59,7 +59,7 @@ export default function BlogPostShow() { {"ID"} - + {"Title"} diff --git a/refine-remix/plugins/mui-example/app/routes/_layout.categories.show.$id.tsx b/refine-remix/plugins/mui-example/app/routes/_layout.categories.show.$id.tsx index 0363ecda..018d87fa 100644 --- a/refine-remix/plugins/mui-example/app/routes/_layout.categories.show.$id.tsx +++ b/refine-remix/plugins/mui-example/app/routes/_layout.categories.show.$id.tsx @@ -35,7 +35,7 @@ export default function CategoryShow() { {"ID"} - + {"Title"} diff --git a/refine-vite/plugins/antd-example/src/pages/blog-posts/show.tsx b/refine-vite/plugins/antd-example/src/pages/blog-posts/show.tsx index ef3867fd..9b7e718e 100644 --- a/refine-vite/plugins/antd-example/src/pages/blog-posts/show.tsx +++ b/refine-vite/plugins/antd-example/src/pages/blog-posts/show.tsx @@ -58,7 +58,7 @@ export const BlogPostShow = () => { return ( {"ID"} - + {"Title"} {"Content"} diff --git a/refine-vite/plugins/antd-example/src/pages/categories/show.tsx b/refine-vite/plugins/antd-example/src/pages/categories/show.tsx index c98a4e92..e6297c6f 100644 --- a/refine-vite/plugins/antd-example/src/pages/categories/show.tsx +++ b/refine-vite/plugins/antd-example/src/pages/categories/show.tsx @@ -31,7 +31,7 @@ export const CategoryShow = () => { return ( {"ID"} - + {"Title"} diff --git a/refine-vite/plugins/mui-example/src/pages/blog-posts/show.tsx b/refine-vite/plugins/mui-example/src/pages/blog-posts/show.tsx index a14c7713..0df95b61 100644 --- a/refine-vite/plugins/mui-example/src/pages/blog-posts/show.tsx +++ b/refine-vite/plugins/mui-example/src/pages/blog-posts/show.tsx @@ -60,7 +60,7 @@ export const BlogPostShow = () => { {"ID"} - + {"Title"} diff --git a/refine-vite/plugins/mui-example/src/pages/categories/show.tsx b/refine-vite/plugins/mui-example/src/pages/categories/show.tsx index ba1a19a2..28edbb8c 100644 --- a/refine-vite/plugins/mui-example/src/pages/categories/show.tsx +++ b/refine-vite/plugins/mui-example/src/pages/categories/show.tsx @@ -35,7 +35,7 @@ export const CategoryShow = () => { {"ID"} - + {"Title"}