Simplify the tanstack auth block.

This commit is contained in:
Ivan Vasilov
2025-03-23 13:03:51 +01:00
parent 1ba5c223d9
commit 258bfb1015
4 changed files with 15 additions and 24 deletions
@@ -9,23 +9,7 @@ description: Supabase client for Tanstack Start
1. Follow the steps in /ui/docs/tanstack/password-based-auth to setup your repo.
2. Add the following property to your `createRootRoute` function:
```ts
import { fetchUser } from "@/lib/supabase/fetch-user-server-fn";
...
beforeLoad: async () => {
const user = await fetchUser();
return {
user,
};
},
...
```
3. Try to access the /info route, you should be redirected to login screen. If you create an account and try accessing the /info page, you should see your email.
2. Try to access the /info route, you should be redirected to login screen. If you create an account and login and try accessing the /info page, you should see your email.
## Folder structure
@@ -29,7 +29,7 @@
},
{
"path": "registry/default/blocks/password-based-auth-tanstack/routes/_protected.tsx",
"content": "import { createFileRoute, redirect } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/_protected')({\n beforeLoad: ({ context }) => {\n if (!context.user) {\n throw redirect({ to: '/login' })\n }\n },\n})\n",
"content": "import { fetchUser } from '@/registry/default/blocks/password-based-auth-tanstack/lib/supabase/fetch-user-server-fn'\nimport { createFileRoute, redirect } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/_protected')({\n beforeLoad: async () => {\n const user = await fetchUser()\n\n if (!user) {\n throw redirect({ to: '/login' })\n }\n\n return {\n user,\n }\n },\n})\n",
"type": "registry:file",
"target": "routes/_protected.tsx"
},
@@ -41,7 +41,7 @@
},
{
"path": "registry/default/blocks/password-based-auth-tanstack/routes/auth/confirm.ts",
"content": "import { createClient } from '@/registry/default/clients/tanstack/lib/supabase/server'\nimport { type EmailOtpType } from '@supabase/supabase-js'\nimport { createFileRoute, redirect } from '@tanstack/react-router'\nimport { createServerFn } from '@tanstack/react-start'\nimport { getWebRequest } from '@tanstack/react-start/server'\n\nconst confirmFn = createServerFn({ method: 'GET' })\n .validator((searchParams: unknown) => {\n if (\n searchParams &&\n typeof searchParams === 'object' &&\n 'token_hash' in searchParams &&\n 'type' in searchParams &&\n 'next' in searchParams\n ) {\n return searchParams\n }\n throw new Error('Invalid search params')\n })\n .handler(async (ctx) => {\n const request = getWebRequest()\n\n if (!request) {\n throw redirect({ to: `/auth/error`, params: { error: 'No request' } })\n }\n\n const searchParams = ctx.data\n const token_hash = searchParams['token_hash'] as string\n const type = searchParams['type'] as EmailOtpType | null\n const next = (searchParams['next'] ?? '/') as string\n\n if (token_hash && type) {\n const supabase = createClient()\n\n const { error } = await supabase.auth.verifyOtp({\n type,\n token_hash,\n })\n console.log(error?.message)\n if (!error) {\n // redirect user to specified redirect URL or root of app\n throw redirect({ href: next })\n } else {\n // redirect the user to an error page with some instructions\n throw redirect({\n to: `/auth/error`,\n params: { error: error?.message },\n })\n }\n }\n\n // redirect the user to an error page with some instructions\n throw redirect({\n to: `/auth/error`,\n params: { error: 'No token hash or type' },\n })\n })\n\nexport const Route = createFileRoute('/auth/confirm')({\n preload: false,\n loader: (opts) => confirmFn({ data: opts.location.search }),\n})\n",
"content": "import { createClient } from '@/registry/default/clients/tanstack/lib/supabase/server'\nimport { type EmailOtpType } from '@supabase/supabase-js'\nimport { createFileRoute, redirect } from '@tanstack/react-router'\nimport { createServerFn } from '@tanstack/react-start'\nimport { getWebRequest } from '@tanstack/react-start/server'\n\nconst confirmFn = createServerFn({ method: 'GET' })\n .validator((searchParams: unknown) => {\n if (\n searchParams &&\n typeof searchParams === 'object' &&\n 'token_hash' in searchParams &&\n 'type' in searchParams &&\n 'next' in searchParams\n ) {\n return searchParams\n }\n throw new Error('Invalid search params')\n })\n .handler(async (ctx) => {\n const request = getWebRequest()\n\n if (!request) {\n throw redirect({ to: `/auth/error`, search: { error: 'No request' } })\n }\n\n const searchParams = ctx.data\n const token_hash = searchParams['token_hash'] as string\n const type = searchParams['type'] as EmailOtpType | null\n const next = (searchParams['next'] ?? '/') as string\n\n if (token_hash && type) {\n const supabase = createClient()\n\n const { error } = await supabase.auth.verifyOtp({\n type,\n token_hash,\n })\n console.log(error?.message)\n if (!error) {\n // redirect user to specified redirect URL or root of app\n throw redirect({ href: next })\n } else {\n // redirect the user to an error page with some instructions\n throw redirect({\n to: `/auth/error`,\n search: { error: error?.message },\n })\n }\n }\n\n // redirect the user to an error page with some instructions\n throw redirect({\n to: `/auth/error`,\n search: { error: 'No token hash or type' },\n })\n })\n\nexport const Route = createFileRoute('/auth/confirm')({\n preload: false,\n loader: (opts) => confirmFn({ data: opts.location.search }),\n})\n",
"type": "registry:file",
"target": "routes/auth/confirm.ts"
},
@@ -1,9 +1,16 @@
import { fetchUser } from '@/registry/default/blocks/password-based-auth-tanstack/lib/supabase/fetch-user-server-fn'
import { createFileRoute, redirect } from '@tanstack/react-router'
export const Route = createFileRoute('/_protected')({
beforeLoad: ({ context }) => {
if (!context.user) {
beforeLoad: async () => {
const user = await fetchUser()
if (!user) {
throw redirect({ to: '/login' })
}
return {
user,
}
},
})
@@ -21,7 +21,7 @@ const confirmFn = createServerFn({ method: 'GET' })
const request = getWebRequest()
if (!request) {
throw redirect({ to: `/auth/error`, params: { error: 'No request' } })
throw redirect({ to: `/auth/error`, search: { error: 'No request' } })
}
const searchParams = ctx.data
@@ -44,7 +44,7 @@ const confirmFn = createServerFn({ method: 'GET' })
// redirect the user to an error page with some instructions
throw redirect({
to: `/auth/error`,
params: { error: error?.message },
search: { error: error?.message },
})
}
}
@@ -52,7 +52,7 @@ const confirmFn = createServerFn({ method: 'GET' })
// redirect the user to an error page with some instructions
throw redirect({
to: `/auth/error`,
params: { error: 'No token hash or type' },
search: { error: 'No token hash or type' },
})
})